From 9e1c3487d1664f6d2fd687b4ea08ce3b3730b2c5 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Tue, 22 Oct 2024 11:38:12 -0400 Subject: [PATCH 01/17] Use RFC-compliant HeaderValue type. When "header-value" feature is enabled, a RFC-compliant HeaderValue type is used instead of the previously used UTF-8 String type. Since HTTP field values aren't UTF-8 encoded, using the String type meant that a plugin would crash when valid, but obsolete, non-UTF-8 characters were present in HTTP headers and/or trailers. This feature is currently optional to avoid breaking changes and to help with migration, but it will become a default feature in v0.3. The HeaderValue type is re-exported from the http crate. Signed-off-by: Piotr Sikora --- .github/workflows/rust.yml | 20 +++ BUILD | 29 ++++ Cargo.toml | 5 + README.md | 7 + bazel/cargo/Cargo.Bazel.lock | 30 ++++ bazel/cargo/remote/BUILD.bazel | 6 + bazel/cargo/remote/BUILD.bytes-1.8.0.bazel | 85 +++++++++ bazel/cargo/remote/BUILD.fnv-1.0.7.bazel | 85 +++++++++ bazel/cargo/remote/BUILD.http-1.1.0.bazel | 90 ++++++++++ bazel/cargo/remote/BUILD.itoa-1.0.11.bazel | 81 +++++++++ bazel/cargo/remote/defs.bzl | 42 +++++ examples/grpc_auth_random/Cargo.toml | 2 +- examples/grpc_auth_random/src/lib.rs | 8 +- examples/http_headers/Cargo.toml | 2 +- examples/http_headers/src/lib.rs | 19 ++- src/hostcalls.rs | 189 +++++++++++++-------- src/traits.rs | 168 ++++++++++++++++++ src/types.rs | 3 + 18 files changed, 791 insertions(+), 80 deletions(-) create mode 100644 bazel/cargo/remote/BUILD.bytes-1.8.0.bazel create mode 100644 bazel/cargo/remote/BUILD.fnv-1.0.7.bazel create mode 100644 bazel/cargo/remote/BUILD.http-1.1.0.bazel create mode 100644 bazel/cargo/remote/BUILD.itoa-1.0.11.bazel diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index da9683f9..757fb6bf 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -94,7 +94,9 @@ jobs: - name: Format (rules_rust) run: | + sed -i'' -E 's/^default = \[\]/default = \[\"header-value\"\]/' Cargo.toml bazelisk --noworkspace_rc run --noenable_bzlmod //bazel/cargo:crates_vendor + git checkout Cargo.toml git diff --exit-code msrv: @@ -148,6 +150,12 @@ jobs: - name: Clippy (wasm32-wasi) run: cargo clippy --release --all-targets --target=wasm32-wasi + - name: Build (header-value) + run: cargo build --release --all-targets --target=wasm32-wasi --features header-value + + - name: Clippy (header-value) + run: cargo clippy --release --all-targets --target=wasm32-wasi --features header-value + - name: Format (rustfmt) run: cargo fmt -- --check @@ -210,6 +218,12 @@ jobs: - name: Clippy (wasm32-wasip1) run: cargo clippy --release --all-targets --target=wasm32-wasip1 + - name: Build (header-value) + run: cargo build --release --all-targets --target=wasm32-wasip1 --features header-value + + - name: Clippy (header-value) + run: cargo clippy --release --all-targets --target=wasm32-wasip1 --features header-value + - name: Format (rustfmt) run: cargo fmt -- --check @@ -273,6 +287,12 @@ jobs: - name: Clippy (wasm32-wasip1) run: cargo clippy --release --all-targets --target=wasm32-wasip1 + - name: Build (header-value) + run: cargo build --release --all-targets --target=wasm32-wasip1 --features header-value + + - name: Clippy (header-value) + run: cargo clippy --release --all-targets --target=wasm32-wasip1 --features header-value + - name: Format (rustfmt) run: cargo fmt -- --check diff --git a/BUILD b/BUILD index 7f611e4f..6af16d0d 100644 --- a/BUILD +++ b/BUILD @@ -39,6 +39,21 @@ rust_library( ], ) +rust_library( + name = "proxy_wasm_header_value", + srcs = glob(["src/*.rs"]), + crate_features = ["header-value"], + crate_name = "proxy_wasm", + edition = "2018", + visibility = ["//visibility:public"], + deps = [ + ":proxy_wasm_build_script", + "//bazel/cargo/remote:hashbrown", + "//bazel/cargo/remote:http", + "//bazel/cargo/remote:log", + ], +) + rust_binary( name = "http_auth_random", srcs = ["examples/http_auth_random/src/lib.rs"], @@ -52,3 +67,17 @@ rust_binary( "//bazel/cargo/remote:log", ], ) + +rust_binary( + name = "grpc_auth_random", + srcs = ["examples/grpc_auth_random/src/lib.rs"], + crate_type = "cdylib", + edition = "2018", + out_binary = True, + rustc_flags = ["-Cstrip=debuginfo"], + visibility = ["//visibility:private"], + deps = [ + ":proxy_wasm_header_value", + "//bazel/cargo/remote:log", + ], +) diff --git a/Cargo.toml b/Cargo.toml index 24193eb8..a52f0d8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,13 @@ build = "build.rs" [dependencies] hashbrown = "0.15" +http = { version = "1", optional = true } log = "0.4" +[features] +default = [] +header-value = ["dep:http"] + [profile.release] lto = true opt-level = 3 diff --git a/README.md b/README.md index 7db3cdc2..404499d8 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,13 @@ [license-badge]: https://img.shields.io/github/license/proxy-wasm/proxy-wasm-rust-sdk [license-link]: https://github.com/proxy-wasm/proxy-wasm-rust-sdk/blob/main/LICENSE +## Crate features + +This crate supports the following optional features: + +- `header-value` - uses RFC-compliant `HeaderValue` instead of UTF-8 `String` for HTTP header and trailer values. + This will become the default in future releases. + ## Examples - [Hello World](./examples/hello_world/) diff --git a/bazel/cargo/Cargo.Bazel.lock b/bazel/cargo/Cargo.Bazel.lock index f4d451ea..367a120e 100644 --- a/bazel/cargo/Cargo.Bazel.lock +++ b/bazel/cargo/Cargo.Bazel.lock @@ -8,12 +8,24 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "foldhash" version = "0.1.3" @@ -31,6 +43,23 @@ dependencies = [ "foldhash", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "log" version = "0.4.22" @@ -42,5 +71,6 @@ name = "proxy-wasm" version = "0.2.3-dev" dependencies = [ "hashbrown", + "http", "log", ] diff --git a/bazel/cargo/remote/BUILD.bazel b/bazel/cargo/remote/BUILD.bazel index f62c1da8..0e16b637 100644 --- a/bazel/cargo/remote/BUILD.bazel +++ b/bazel/cargo/remote/BUILD.bazel @@ -37,6 +37,12 @@ alias( tags = ["manual"], ) +alias( + name = "http", + actual = "@crates_vendor__http-1.1.0//:http", + tags = ["manual"], +) + alias( name = "log", actual = "@crates_vendor__log-0.4.22//:log", diff --git a/bazel/cargo/remote/BUILD.bytes-1.8.0.bazel b/bazel/cargo/remote/BUILD.bytes-1.8.0.bazel new file mode 100644 index 00000000..efac2269 --- /dev/null +++ b/bazel/cargo/remote/BUILD.bytes-1.8.0.bazel @@ -0,0 +1,85 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @//bazel/cargo:crates_vendor +############################################################################### + +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +rust_library( + name = "bytes", + srcs = glob( + include = ["**/*.rs"], + allow_empty = True, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=bytes", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-fuchsia": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasi": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-fuchsia": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.8.0", +) diff --git a/bazel/cargo/remote/BUILD.fnv-1.0.7.bazel b/bazel/cargo/remote/BUILD.fnv-1.0.7.bazel new file mode 100644 index 00000000..39a1f179 --- /dev/null +++ b/bazel/cargo/remote/BUILD.fnv-1.0.7.bazel @@ -0,0 +1,85 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @//bazel/cargo:crates_vendor +############################################################################### + +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +rust_library( + name = "fnv", + srcs = glob( + include = ["**/*.rs"], + allow_empty = True, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "default", + "std", + ], + crate_root = "lib.rs", + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=fnv", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-fuchsia": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasi": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-fuchsia": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.0.7", +) diff --git a/bazel/cargo/remote/BUILD.http-1.1.0.bazel b/bazel/cargo/remote/BUILD.http-1.1.0.bazel new file mode 100644 index 00000000..51969aca --- /dev/null +++ b/bazel/cargo/remote/BUILD.http-1.1.0.bazel @@ -0,0 +1,90 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @//bazel/cargo:crates_vendor +############################################################################### + +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +rust_library( + name = "http", + srcs = glob( + include = ["**/*.rs"], + allow_empty = True, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=http", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-fuchsia": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasi": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-fuchsia": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.1.0", + deps = [ + "@crates_vendor__bytes-1.8.0//:bytes", + "@crates_vendor__fnv-1.0.7//:fnv", + "@crates_vendor__itoa-1.0.11//:itoa", + ], +) diff --git a/bazel/cargo/remote/BUILD.itoa-1.0.11.bazel b/bazel/cargo/remote/BUILD.itoa-1.0.11.bazel new file mode 100644 index 00000000..d8c549e8 --- /dev/null +++ b/bazel/cargo/remote/BUILD.itoa-1.0.11.bazel @@ -0,0 +1,81 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @//bazel/cargo:crates_vendor +############################################################################### + +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +rust_library( + name = "itoa", + srcs = glob( + include = ["**/*.rs"], + allow_empty = True, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_root = "src/lib.rs", + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=itoa", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-fuchsia": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasi": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-fuchsia": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.0.11", +) diff --git a/bazel/cargo/remote/defs.bzl b/bazel/cargo/remote/defs.bzl index e4051261..9f2308c6 100644 --- a/bazel/cargo/remote/defs.bzl +++ b/bazel/cargo/remote/defs.bzl @@ -296,6 +296,7 @@ _NORMAL_DEPENDENCIES = { "": { _COMMON_CONDITION: { "hashbrown": Label("@crates_vendor__hashbrown-0.15.0//:hashbrown"), + "http": Label("@crates_vendor__http-1.1.0//:http"), "log": Label("@crates_vendor__log-0.4.22//:log"), }, }, @@ -413,6 +414,16 @@ def crate_repositories(): build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.allocator-api2-0.2.18.bazel"), ) + maybe( + http_archive, + name = "crates_vendor__bytes-1.8.0", + sha256 = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da", + type = "tar.gz", + urls = ["https://static.crates.io/crates/bytes/1.8.0/download"], + strip_prefix = "bytes-1.8.0", + build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.bytes-1.8.0.bazel"), + ) + maybe( http_archive, name = "crates_vendor__equivalent-1.0.1", @@ -423,6 +434,16 @@ def crate_repositories(): build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.equivalent-1.0.1.bazel"), ) + maybe( + http_archive, + name = "crates_vendor__fnv-1.0.7", + sha256 = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1", + type = "tar.gz", + urls = ["https://static.crates.io/crates/fnv/1.0.7/download"], + strip_prefix = "fnv-1.0.7", + build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.fnv-1.0.7.bazel"), + ) + maybe( http_archive, name = "crates_vendor__foldhash-0.1.3", @@ -443,6 +464,26 @@ def crate_repositories(): build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.hashbrown-0.15.0.bazel"), ) + maybe( + http_archive, + name = "crates_vendor__http-1.1.0", + sha256 = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258", + type = "tar.gz", + urls = ["https://static.crates.io/crates/http/1.1.0/download"], + strip_prefix = "http-1.1.0", + build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.http-1.1.0.bazel"), + ) + + maybe( + http_archive, + name = "crates_vendor__itoa-1.0.11", + sha256 = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b", + type = "tar.gz", + urls = ["https://static.crates.io/crates/itoa/1.0.11/download"], + strip_prefix = "itoa-1.0.11", + build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.itoa-1.0.11.bazel"), + ) + maybe( http_archive, name = "crates_vendor__log-0.4.22", @@ -455,5 +496,6 @@ def crate_repositories(): return [ struct(repo = "crates_vendor__hashbrown-0.15.0", is_dev_dep = False), + struct(repo = "crates_vendor__http-1.1.0", is_dev_dep = False), struct(repo = "crates_vendor__log-0.4.22", is_dev_dep = False), ] diff --git a/examples/grpc_auth_random/Cargo.toml b/examples/grpc_auth_random/Cargo.toml index c3e6ec01..3e5b3be6 100644 --- a/examples/grpc_auth_random/Cargo.toml +++ b/examples/grpc_auth_random/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib"] [dependencies] log = "0.4" -proxy-wasm = { path = "../../" } +proxy-wasm = { path = "../../", features = ["header-value"] } [profile.release] lto = true diff --git a/examples/grpc_auth_random/src/lib.rs b/examples/grpc_auth_random/src/lib.rs index d1c589e9..11df530e 100644 --- a/examples/grpc_auth_random/src/lib.rs +++ b/examples/grpc_auth_random/src/lib.rs @@ -27,12 +27,12 @@ struct GrpcAuthRandom; impl HttpContext for GrpcAuthRandom { fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action { match self.get_http_request_header("content-type") { - Some(value) if value.starts_with("application/grpc") => {} + Some(value) if value.as_bytes().starts_with(b"application/grpc") => {} _ => { // Reject non-gRPC clients. self.send_http_response( 503, - vec![("Powered-By", "proxy-wasm")], + vec![("Powered-By", &HeaderValue::from_static("proxy-wasm"))], Some(b"Service accessible only to gRPC clients.\n"), ); return Action::Pause; @@ -40,7 +40,7 @@ impl HttpContext for GrpcAuthRandom { } match self.get_http_request_header(":path") { - Some(value) if value.starts_with("/grpc.reflection") => { + Some(value) if value.as_bytes().starts_with(b"/grpc.reflection") => { // Always allow gRPC calls to the reflection API. Action::Continue } @@ -61,7 +61,7 @@ impl HttpContext for GrpcAuthRandom { } fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action { - self.set_http_response_header("Powered-By", Some("proxy-wasm")); + self.set_http_response_header("Powered-By", Some(&HeaderValue::from_static("proxy-wasm"))); Action::Continue } } diff --git a/examples/http_headers/Cargo.toml b/examples/http_headers/Cargo.toml index 02afd242..2fb8fa6a 100644 --- a/examples/http_headers/Cargo.toml +++ b/examples/http_headers/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["cdylib"] [dependencies] log = "0.4" -proxy-wasm = { path = "../../" } +proxy-wasm = { path = "../../", features = ["header-value"] } [profile.release] lto = true diff --git a/examples/http_headers/src/lib.rs b/examples/http_headers/src/lib.rs index 315a7b88..a6a4942b 100644 --- a/examples/http_headers/src/lib.rs +++ b/examples/http_headers/src/lib.rs @@ -44,14 +44,22 @@ impl Context for HttpHeaders {} impl HttpContext for HttpHeaders { fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action { for (name, value) in &self.get_http_request_headers() { - info!("#{} -> {}: {}", self.context_id, name, value); + info!( + "#{} -> {}: {}", + self.context_id, + name, + value.to_str().unwrap_or("") + ); } match self.get_http_request_header(":path") { Some(path) if path == "/hello" => { self.send_http_response( 200, - vec![("Hello", "World"), ("Powered-By", "proxy-wasm")], + vec![ + ("Hello", &HeaderValue::from_static("World")), + ("Powered-By", &HeaderValue::from_static("proxy-wasm")), + ], Some(b"Hello, World!\n"), ); Action::Pause @@ -62,7 +70,12 @@ impl HttpContext for HttpHeaders { fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action { for (name, value) in &self.get_http_response_headers() { - info!("#{} <- {}: {}", self.context_id, name, value); + info!( + "#{} <- {}: {}", + self.context_id, + name, + value.to_str().unwrap_or("") + ); } Action::Continue } diff --git a/src/hostcalls.rs b/src/hostcalls.rs index 15687888..68059899 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -145,6 +145,26 @@ extern "C" { ) -> Status; } +#[cfg(feature = "header-value")] +pub fn get_map(map_type: MapType) -> Result, Status> { + unsafe { + let mut return_data: *mut u8 = null_mut(); + let mut return_size: usize = 0; + match proxy_get_header_map_pairs(map_type, &mut return_data, &mut return_size) { + Status::Ok => { + if !return_data.is_null() { + let serialized_map = Vec::from_raw_parts(return_data, return_size, return_size); + Ok(utils::deserialize_map(&serialized_map)) + } else { + Ok(Vec::new()) + } + } + status => panic!("unexpected status: {}", status as u32), + } + } +} + +#[cfg(not(feature = "header-value"))] pub fn get_map(map_type: MapType) -> Result, Status> { unsafe { let mut return_data: *mut u8 = null_mut(); @@ -189,7 +209,10 @@ extern "C" { ) -> Status; } -pub fn set_map(map_type: MapType, map: Vec<(&str, &str)>) -> Result<(), Status> { +pub fn set_map(map_type: MapType, map: Vec<(&str, V)>) -> Result<(), Status> +where + V: AsRef<[u8]>, +{ let serialized_map = utils::serialize_map(map); unsafe { match proxy_set_header_map_pairs(map_type, serialized_map.as_ptr(), serialized_map.len()) { @@ -200,13 +223,7 @@ pub fn set_map(map_type: MapType, map: Vec<(&str, &str)>) -> Result<(), Status> } pub fn set_map_bytes(map_type: MapType, map: Vec<(&str, &[u8])>) -> Result<(), Status> { - let serialized_map = utils::serialize_map_bytes(map); - unsafe { - match proxy_set_header_map_pairs(map_type, serialized_map.as_ptr(), serialized_map.len()) { - Status::Ok => Ok(()), - status => panic!("unexpected status: {}", status as u32), - } - } + set_map(map_type, map) } extern "C" { @@ -219,6 +236,38 @@ extern "C" { ) -> Status; } +#[cfg(feature = "header-value")] +pub fn get_map_value(map_type: MapType, key: &str) -> Result, Status> { + let mut return_data: *mut u8 = null_mut(); + let mut return_size: usize = 0; + unsafe { + match proxy_get_header_map_value( + map_type, + key.as_ptr(), + key.len(), + &mut return_data, + &mut return_size, + ) { + Status::Ok => { + if !return_data.is_null() { + match HeaderValue::from_bytes(std::slice::from_raw_parts( + return_data, + return_size, + )) { + Ok(value) => Ok(Some(value)), + Err(_) => panic!("illegal field value in: {}", key), + } + } else { + Ok(None) + } + } + Status::NotFound => Ok(None), + status => panic!("unexpected status: {}", status as u32), + } + } +} + +#[cfg(not(feature = "header-value"))] pub fn get_map_value(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; @@ -296,15 +345,18 @@ extern "C" { ) -> Status; } -pub fn set_map_value(map_type: MapType, key: &str, value: Option<&str>) -> Result<(), Status> { +pub fn set_map_value(map_type: MapType, key: &str, value: Option) -> Result<(), Status> +where + V: AsRef<[u8]>, +{ unsafe { if let Some(value) = value { match proxy_replace_header_map_value( map_type, key.as_ptr(), key.len(), - value.as_ptr(), - value.len(), + value.as_ref().as_ptr(), + value.as_ref().len(), ) { Status::Ok => Ok(()), status => panic!("unexpected status: {}", status as u32), @@ -323,25 +375,7 @@ pub fn set_map_value_bytes( key: &str, value: Option<&[u8]>, ) -> Result<(), Status> { - unsafe { - if let Some(value) = value { - match proxy_replace_header_map_value( - map_type, - key.as_ptr(), - key.len(), - value.as_ptr(), - value.len(), - ) { - Status::Ok => Ok(()), - status => panic!("unexpected status: {}", status as u32), - } - } else { - match proxy_remove_header_map_value(map_type, key.as_ptr(), key.len()) { - Status::Ok => Ok(()), - status => panic!("unexpected status: {}", status as u32), - } - } - } + set_map_value(map_type, key, value) } extern "C" { @@ -354,14 +388,17 @@ extern "C" { ) -> Status; } -pub fn add_map_value(map_type: MapType, key: &str, value: &str) -> Result<(), Status> { +pub fn add_map_value(map_type: MapType, key: &str, value: V) -> Result<(), Status> +where + V: AsRef<[u8]>, +{ unsafe { match proxy_add_header_map_value( map_type, key.as_ptr(), key.len(), - value.as_ptr(), - value.len(), + value.as_ref().as_ptr(), + value.as_ref().len(), ) { Status::Ok => Ok(()), status => panic!("unexpected status: {}", status as u32), @@ -370,18 +407,7 @@ pub fn add_map_value(map_type: MapType, key: &str, value: &str) -> Result<(), St } pub fn add_map_value_bytes(map_type: MapType, key: &str, value: &[u8]) -> Result<(), Status> { - unsafe { - match proxy_add_header_map_value( - map_type, - key.as_ptr(), - key.len(), - value.as_ptr(), - value.len(), - ) { - Status::Ok => Ok(()), - status => panic!("unexpected status: {}", status as u32), - } - } + add_map_value(map_type, key, value) } extern "C" { @@ -705,11 +731,14 @@ extern "C" { ) -> Status; } -pub fn send_http_response( +pub fn send_http_response( status_code: u32, - headers: Vec<(&str, &str)>, + headers: Vec<(&str, V)>, body: Option<&[u8]>, -) -> Result<(), Status> { +) -> Result<(), Status> +where + V: AsRef<[u8]>, +{ let serialized_headers = utils::serialize_map(headers); unsafe { match proxy_send_local_response( @@ -766,13 +795,16 @@ extern "C" { ) -> Status; } -pub fn dispatch_http_call( +pub fn dispatch_http_call( upstream: &str, - headers: Vec<(&str, &str)>, + headers: Vec<(&str, V)>, body: Option<&[u8]>, - trailers: Vec<(&str, &str)>, + trailers: Vec<(&str, V)>, timeout: Duration, -) -> Result { +) -> Result +where + V: AsRef<[u8]>, +{ let serialized_headers = utils::serialize_map(headers); let serialized_trailers = utils::serialize_map(trailers); let mut return_token: u32 = 0; @@ -1140,6 +1172,8 @@ pub fn increment_metric(metric_id: u32, offset: i64) -> Result<(), Status> { mod utils { use crate::types::Bytes; + #[cfg(feature = "header-value")] + use crate::types::HeaderValue; use std::convert::TryFrom; pub(super) fn serialize_property_path(path: Vec<&str>) -> Bytes { @@ -1159,46 +1193,59 @@ mod utils { bytes } - pub(super) fn serialize_map(map: Vec<(&str, &str)>) -> Bytes { + pub(super) fn serialize_map(map: Vec<(&str, V)>) -> Bytes + where + V: AsRef<[u8]>, + { let mut size: usize = 4; for (name, value) in &map { - size += name.len() + value.len() + 10; + size += name.len() + value.as_ref().len() + 10; } let mut bytes: Bytes = Vec::with_capacity(size); bytes.extend_from_slice(&map.len().to_le_bytes()); for (name, value) in &map { bytes.extend_from_slice(&name.len().to_le_bytes()); - bytes.extend_from_slice(&value.len().to_le_bytes()); + bytes.extend_from_slice(&value.as_ref().len().to_le_bytes()); } for (name, value) in &map { bytes.extend_from_slice(name.as_bytes()); bytes.push(0); - bytes.extend_from_slice(value.as_bytes()); + bytes.extend_from_slice(value.as_ref()); bytes.push(0); } bytes } pub(super) fn serialize_map_bytes(map: Vec<(&str, &[u8])>) -> Bytes { - let mut size: usize = 4; - for (name, value) in &map { - size += name.len() + value.len() + 10; - } - let mut bytes: Bytes = Vec::with_capacity(size); - bytes.extend_from_slice(&map.len().to_le_bytes()); - for (name, value) in &map { - bytes.extend_from_slice(&name.len().to_le_bytes()); - bytes.extend_from_slice(&value.len().to_le_bytes()); + serialize_map(map) + } + + #[cfg(feature = "header-value")] + pub(super) fn deserialize_map(bytes: &[u8]) -> Vec<(String, HeaderValue)> { + let mut map = Vec::new(); + if bytes.is_empty() { + return map; } - for (name, value) in &map { - bytes.extend_from_slice(name.as_bytes()); - bytes.push(0); - bytes.extend_from_slice(value); - bytes.push(0); + let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[0..4]).unwrap()) as usize; + let mut p = 4 + size * 8; + for n in 0..size { + let s = 4 + n * 8; + let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s..s + 4]).unwrap()) as usize; + let key = bytes[p..p + size].to_vec(); + p += size + 1; + let size = + u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s + 4..s + 8]).unwrap()) as usize; + let value = &bytes[p..p + size]; + p += size + 1; + map.push(( + String::from_utf8(key).unwrap(), + HeaderValue::from_bytes(value).unwrap(), + )); } - bytes + map } + #[cfg(not(feature = "header-value"))] pub(super) fn deserialize_map(bytes: &[u8]) -> Vec<(String, String)> { let mut map = Vec::new(); if bytes.is_empty() { diff --git a/src/traits.rs b/src/traits.rs index bd54bcbe..63a3db97 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -58,6 +58,19 @@ pub trait Context { hostcalls::enqueue_shared_queue(queue_id, value) } + #[cfg(feature = "header-value")] + fn dispatch_http_call( + &self, + upstream: &str, + headers: Vec<(&str, &HeaderValue)>, + body: Option<&[u8]>, + trailers: Vec<(&str, &HeaderValue)>, + timeout: Duration, + ) -> Result { + hostcalls::dispatch_http_call(upstream, headers, body, trailers, timeout) + } + + #[cfg(not(feature = "header-value"))] fn dispatch_http_call( &self, upstream: &str, @@ -78,6 +91,12 @@ pub trait Context { ) { } + #[cfg(feature = "header-value")] + fn get_http_call_response_headers(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map(MapType::HttpCallResponseHeaders).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_call_response_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpCallResponseHeaders).unwrap() } @@ -86,6 +105,12 @@ pub trait Context { hostcalls::get_map_bytes(MapType::HttpCallResponseHeaders).unwrap() } + #[cfg(feature = "header-value")] + fn get_http_call_response_header(&self, name: &str) -> Option { + hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_call_response_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseHeaders, name).unwrap() } @@ -98,6 +123,12 @@ pub trait Context { hostcalls::get_buffer(BufferType::HttpCallResponseBody, start, max_size).unwrap() } + #[cfg(feature = "header-value")] + fn get_http_call_response_trailers(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map(MapType::HttpCallResponseTrailers).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_call_response_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpCallResponseTrailers).unwrap() } @@ -106,6 +137,12 @@ pub trait Context { hostcalls::get_map_bytes(MapType::HttpCallResponseTrailers).unwrap() } + #[cfg(feature = "header-value")] + fn get_http_call_response_trailer(&self, name: &str) -> Option { + hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_call_response_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() } @@ -311,6 +348,12 @@ pub trait HttpContext: Context { Action::Continue } + #[cfg(feature = "header-value")] + fn get_http_request_headers(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map(MapType::HttpRequestHeaders).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_request_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestHeaders).unwrap() } @@ -319,6 +362,12 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpRequestHeaders).unwrap() } + #[cfg(feature = "header-value")] + fn set_http_request_headers(&self, headers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map(MapType::HttpRequestHeaders, headers).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn set_http_request_headers(&self, headers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpRequestHeaders, headers).unwrap() } @@ -327,6 +376,12 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpRequestHeaders, headers).unwrap() } + #[cfg(feature = "header-value")] + fn get_http_request_header(&self, name: &str) -> Option { + hostcalls::get_map_value(MapType::HttpRequestHeaders, name).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_request_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestHeaders, name).unwrap() } @@ -335,6 +390,12 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpRequestHeaders, name).unwrap() } + #[cfg(feature = "header-value")] + fn set_http_request_header(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value(MapType::HttpRequestHeaders, name, value).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn set_http_request_header(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } @@ -343,6 +404,12 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpRequestHeaders, name, value).unwrap() } + #[cfg(feature = "header-value")] + fn add_http_request_header(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value(MapType::HttpRequestHeaders, name, value).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn add_http_request_header(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } @@ -367,6 +434,12 @@ pub trait HttpContext: Context { Action::Continue } + #[cfg(feature = "header-value")] + fn get_http_request_trailers(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map(MapType::HttpRequestTrailers).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_request_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestTrailers).unwrap() } @@ -375,6 +448,12 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpRequestTrailers).unwrap() } + #[cfg(feature = "header-value")] + fn set_http_request_trailers(&self, trailers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map(MapType::HttpRequestTrailers, trailers).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn set_http_request_trailers(&self, trailers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpRequestTrailers, trailers).unwrap() } @@ -383,6 +462,12 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpRequestTrailers, trailers).unwrap() } + #[cfg(feature = "header-value")] + fn get_http_request_trailer(&self, name: &str) -> Option { + hostcalls::get_map_value(MapType::HttpRequestTrailers, name).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_request_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestTrailers, name).unwrap() } @@ -391,6 +476,12 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpRequestTrailers, name).unwrap() } + #[cfg(feature = "header-value")] + fn set_http_request_trailer(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value(MapType::HttpRequestTrailers, name, value).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn set_http_request_trailer(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } @@ -399,6 +490,12 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpRequestTrailers, name, value).unwrap() } + #[cfg(feature = "header-value")] + fn add_http_request_trailer(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value(MapType::HttpRequestTrailers, name, value).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn add_http_request_trailer(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } @@ -419,6 +516,12 @@ pub trait HttpContext: Context { Action::Continue } + #[cfg(feature = "header-value")] + fn get_http_response_headers(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map(MapType::HttpResponseHeaders).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_response_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseHeaders).unwrap() } @@ -427,6 +530,12 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpResponseHeaders).unwrap() } + #[cfg(feature = "header-value")] + fn set_http_response_headers(&self, headers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map(MapType::HttpResponseHeaders, headers).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn set_http_response_headers(&self, headers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpResponseHeaders, headers).unwrap() } @@ -435,6 +544,12 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpResponseHeaders, headers).unwrap() } + #[cfg(feature = "header-value")] + fn get_http_response_header(&self, name: &str) -> Option { + hostcalls::get_map_value(MapType::HttpResponseHeaders, name).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_response_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseHeaders, name).unwrap() } @@ -443,6 +558,12 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpResponseHeaders, name).unwrap() } + #[cfg(feature = "header-value")] + fn set_http_response_header(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value(MapType::HttpResponseHeaders, name, value).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn set_http_response_header(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } @@ -451,6 +572,12 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpResponseHeaders, name, value).unwrap() } + #[cfg(feature = "header-value")] + fn add_http_response_header(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value(MapType::HttpResponseHeaders, name, value).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn add_http_response_header(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } @@ -475,6 +602,12 @@ pub trait HttpContext: Context { Action::Continue } + #[cfg(feature = "header-value")] + fn get_http_response_trailers(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map(MapType::HttpResponseTrailers).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_response_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseTrailers).unwrap() } @@ -483,6 +616,12 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpResponseTrailers).unwrap() } + #[cfg(feature = "header-value")] + fn set_http_response_trailers(&self, trailers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map(MapType::HttpResponseTrailers, trailers).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn set_http_response_trailers(&self, trailers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpResponseTrailers, trailers).unwrap() } @@ -491,6 +630,12 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpResponseTrailers, trailers).unwrap() } + #[cfg(feature = "header-value")] + fn get_http_response_trailer(&self, name: &str) -> Option { + hostcalls::get_map_value(MapType::HttpResponseTrailers, name).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn get_http_response_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseTrailers, name).unwrap() } @@ -499,6 +644,12 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpResponseTrailers, name).unwrap() } + #[cfg(feature = "header-value")] + fn set_http_response_trailer(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value(MapType::HttpResponseTrailers, name, value).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn set_http_response_trailer(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } @@ -507,6 +658,12 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpResponseTrailers, name, value).unwrap() } + #[cfg(feature = "header-value")] + fn add_http_response_trailer(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value(MapType::HttpResponseTrailers, name, value).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn add_http_response_trailer(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } @@ -523,6 +680,17 @@ pub trait HttpContext: Context { hostcalls::reset_http_response().unwrap() } + #[cfg(feature = "header-value")] + fn send_http_response( + &self, + status_code: u32, + headers: Vec<(&str, &HeaderValue)>, + body: Option<&[u8]>, + ) { + hostcalls::send_http_response(status_code, headers, body).unwrap() + } + + #[cfg(not(feature = "header-value"))] fn send_http_response( &self, status_code: u32, diff --git a/src/types.rs b/src/types.rs index 7407d3ca..36f387e7 100644 --- a/src/types.rs +++ b/src/types.rs @@ -139,3 +139,6 @@ pub enum GrpcStatusCode { } pub type Bytes = Vec; + +#[cfg(feature = "header-value")] +pub use http::HeaderValue; From 0542a785f2cbaf9d9fa36cdf75729cc6a0f71bbd Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sun, 27 Oct 2024 18:29:43 -0400 Subject: [PATCH 02/17] review: retain values from more forgiving hosts. Signed-off-by: Piotr Sikora --- BUILD | 1 + Cargo.toml | 3 ++- bazel/cargo/Cargo.Bazel.lock | 1 + bazel/cargo/remote/BUILD.bazel | 6 +++++ bazel/cargo/remote/defs.bzl | 2 ++ src/hostcalls.rs | 40 +++++++++++++++++++--------------- 6 files changed, 34 insertions(+), 19 deletions(-) diff --git a/BUILD b/BUILD index 6af16d0d..eb96231e 100644 --- a/BUILD +++ b/BUILD @@ -48,6 +48,7 @@ rust_library( visibility = ["//visibility:public"], deps = [ ":proxy_wasm_build_script", + "//bazel/cargo/remote:bytes", "//bazel/cargo/remote:hashbrown", "//bazel/cargo/remote:http", "//bazel/cargo/remote:log", diff --git a/Cargo.toml b/Cargo.toml index a52f0d8c..fd322592 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,13 +11,14 @@ edition = "2018" build = "build.rs" [dependencies] +bytes = { version = "1", optional = true } hashbrown = "0.15" http = { version = "1", optional = true } log = "0.4" [features] default = [] -header-value = ["dep:http"] +header-value = ["dep:bytes", "dep:http"] [profile.release] lto = true diff --git a/bazel/cargo/Cargo.Bazel.lock b/bazel/cargo/Cargo.Bazel.lock index 367a120e..3a373e6d 100644 --- a/bazel/cargo/Cargo.Bazel.lock +++ b/bazel/cargo/Cargo.Bazel.lock @@ -70,6 +70,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" name = "proxy-wasm" version = "0.2.3-dev" dependencies = [ + "bytes", "hashbrown", "http", "log", diff --git a/bazel/cargo/remote/BUILD.bazel b/bazel/cargo/remote/BUILD.bazel index 0e16b637..46e22fdb 100644 --- a/bazel/cargo/remote/BUILD.bazel +++ b/bazel/cargo/remote/BUILD.bazel @@ -31,6 +31,12 @@ filegroup( ) # Workspace Member Dependencies +alias( + name = "bytes", + actual = "@crates_vendor__bytes-1.8.0//:bytes", + tags = ["manual"], +) + alias( name = "hashbrown", actual = "@crates_vendor__hashbrown-0.15.0//:hashbrown", diff --git a/bazel/cargo/remote/defs.bzl b/bazel/cargo/remote/defs.bzl index 9f2308c6..97ddadb4 100644 --- a/bazel/cargo/remote/defs.bzl +++ b/bazel/cargo/remote/defs.bzl @@ -295,6 +295,7 @@ def aliases( _NORMAL_DEPENDENCIES = { "": { _COMMON_CONDITION: { + "bytes": Label("@crates_vendor__bytes-1.8.0//:bytes"), "hashbrown": Label("@crates_vendor__hashbrown-0.15.0//:hashbrown"), "http": Label("@crates_vendor__http-1.1.0//:http"), "log": Label("@crates_vendor__log-0.4.22//:log"), @@ -495,6 +496,7 @@ def crate_repositories(): ) return [ + struct(repo = "crates_vendor__bytes-1.8.0", is_dev_dep = False), struct(repo = "crates_vendor__hashbrown-0.15.0", is_dev_dep = False), struct(repo = "crates_vendor__http-1.1.0", is_dev_dep = False), struct(repo = "crates_vendor__log-0.4.22", is_dev_dep = False), diff --git a/src/hostcalls.rs b/src/hostcalls.rs index 68059899..630bc3e4 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -153,8 +153,9 @@ pub fn get_map(map_type: MapType) -> Result, Status> match proxy_get_header_map_pairs(map_type, &mut return_data, &mut return_size) { Status::Ok => { if !return_data.is_null() { - let serialized_map = Vec::from_raw_parts(return_data, return_size, return_size); - Ok(utils::deserialize_map(&serialized_map)) + let serialized_map = + bytes::Bytes::from(std::slice::from_raw_parts(return_data, return_size)); + Ok(utils::deserialize_map(serialized_map)) } else { Ok(Vec::new()) } @@ -1174,6 +1175,8 @@ mod utils { use crate::types::Bytes; #[cfg(feature = "header-value")] use crate::types::HeaderValue; + #[cfg(feature = "header-value")] + use bytes::Buf; use std::convert::TryFrom; pub(super) fn serialize_property_path(path: Vec<&str>) -> Bytes { @@ -1221,25 +1224,26 @@ mod utils { } #[cfg(feature = "header-value")] - pub(super) fn deserialize_map(bytes: &[u8]) -> Vec<(String, HeaderValue)> { - let mut map = Vec::new(); + pub(super) fn deserialize_map(mut bytes: bytes::Bytes) -> Vec<(String, HeaderValue)> { if bytes.is_empty() { - return map; + return Vec::new(); } - let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[0..4]).unwrap()) as usize; - let mut p = 4 + size * 8; - for n in 0..size { - let s = 4 + n * 8; - let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s..s + 4]).unwrap()) as usize; - let key = bytes[p..p + size].to_vec(); - p += size + 1; - let size = - u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s + 4..s + 8]).unwrap()) as usize; - let value = &bytes[p..p + size]; - p += size + 1; + let size = bytes.get_u32_le() as usize; + let mut sizes = bytes.split_to(size * 8); + let mut map = Vec::with_capacity(size); + for _ in 0..size { + let size = sizes.get_u32_le() as usize; + let key = bytes.split_to(size); + bytes.advance(1); + let size = sizes.get_u32_le() as usize; + let value = bytes.split_to(size); + bytes.advance(1); map.push(( - String::from_utf8(key).unwrap(), - HeaderValue::from_bytes(value).unwrap(), + String::from_utf8(key.to_vec()).unwrap(), + // We're intentionally using the unchecked variant in order to retain + // values accepted by the hosts and proxies that don't enforce strict + // RFC compliance on HTTP field values. + unsafe { HeaderValue::from_maybe_shared_unchecked(value) }, )); } map From 21f1a97f43ecd9b4db066f51c264d6d3a56d530d Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Thu, 5 Jun 2025 01:12:09 -0400 Subject: [PATCH 03/17] review: add comment explaining the panic hook override in tests. Signed-off-by: Piotr Sikora --- src/hostcalls.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hostcalls.rs b/src/hostcalls.rs index a259d946..c74d43f0 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -1472,6 +1472,7 @@ mod utils { // 0x80-0xff are invalid single-byte UTF-8 characters. for i in 0x80..0xff { let serialized_src: &[u8] = &[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; + // Override panic to silence panic logs in the test output. std::panic::set_hook(Box::new(|_| {})); let result = std::panic::catch_unwind(|| { deserialize_map(serialized_src); From ca5ea403ce055741f55b2f68a234fc9011d38607 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Thu, 26 Jun 2025 11:18:51 -0400 Subject: [PATCH 04/17] review: illegal -> invalid. Signed-off-by: Piotr Sikora --- src/hostcalls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hostcalls.rs b/src/hostcalls.rs index c74d43f0..a187b4cc 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -256,7 +256,7 @@ pub fn get_map_value(map_type: MapType, key: &str) -> Result return_size, )) { Ok(value) => Ok(Some(value)), - Err(_) => panic!("illegal field value in: {}", key), + Err(_) => panic!("invalid field value in: {}", key), } } else { Ok(Some(HeaderValue::from_static(""))) From 34b6eb7308f05491f7b98a3efece6f23539102a3 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Thu, 26 Jun 2025 11:25:01 -0400 Subject: [PATCH 05/17] review: header-value -> strict-header-value. Signed-off-by: Piotr Sikora --- .github/workflows/rust.yml | 42 +++++------ BUILD | 6 +- Cargo.toml | 2 +- README.md | 2 +- examples/grpc_auth_random/Cargo.toml | 2 +- examples/http_headers/Cargo.toml | 2 +- src/hostcalls.rs | 24 +++---- src/traits.rs | 104 +++++++++++++-------------- src/types.rs | 2 +- 9 files changed, 93 insertions(+), 93 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2ff86288..247e4dc7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -96,7 +96,7 @@ jobs: - name: Format (rules_rust) run: | - sed -i'' -E 's/^default = \[\]/default = \[\"header-value\"\]/' Cargo.toml + sed -i'' -E 's/^default = \[\]/default = \[\"strict-header-value\"\]/' Cargo.toml bazelisk --noworkspace_rc run --noenable_bzlmod //bazel/cargo:crates_vendor git checkout Cargo.toml git diff --exit-code @@ -152,17 +152,17 @@ jobs: - name: Clippy (wasm32-wasi) run: cargo clippy --release --all-targets --target=wasm32-wasi - - name: Build (header-value) - run: cargo build --release --all-targets --target=wasm32-wasi --features header-value + - name: Build (strict-header-value) + run: cargo build --release --all-targets --target=wasm32-wasi --features strict-header-value - - name: Clippy (header-value) - run: cargo clippy --release --all-targets --target=wasm32-wasi --features header-value + - name: Clippy (strict-header-value) + run: cargo clippy --release --all-targets --target=wasm32-wasi --features strict-header-value - name: Test run: cargo test - - name: Test (header-value) - run: cargo test --features header-value + - name: Test (strict-header-value) + run: cargo test --features strict-header-value - name: Format (rustfmt) run: cargo fmt -- --check @@ -226,17 +226,17 @@ jobs: - name: Clippy (wasm32-wasip1) run: cargo clippy --release --all-targets --target=wasm32-wasip1 - - name: Build (header-value) - run: cargo build --release --all-targets --target=wasm32-wasip1 --features header-value + - name: Build (strict-header-value) + run: cargo build --release --all-targets --target=wasm32-wasip1 --features strict-header-value - - name: Clippy (header-value) - run: cargo clippy --release --all-targets --target=wasm32-wasip1 --features header-value + - name: Clippy (strict-header-value) + run: cargo clippy --release --all-targets --target=wasm32-wasip1 --features strict-header-value - name: Test run: cargo test - - name: Test (header-value) - run: cargo test --features header-value + - name: Test (strict-header-value) + run: cargo test --features strict-header-value - name: Format (rustfmt) run: cargo fmt -- --check @@ -301,23 +301,23 @@ jobs: - name: Clippy (wasm32-wasip1) run: cargo clippy --release --all-targets --target=wasm32-wasip1 - - name: Build (header-value) - run: cargo build --release --all-targets --target=wasm32-wasip1 --features header-value + - name: Build (strict-header-value) + run: cargo build --release --all-targets --target=wasm32-wasip1 --features strict-header-value - - name: Clippy (header-value) - run: cargo clippy --release --all-targets --target=wasm32-wasip1 --features header-value + - name: Clippy (strict-header-value) + run: cargo clippy --release --all-targets --target=wasm32-wasip1 --features strict-header-value - name: Test run: cargo test - - name: Test (header-value) - run: cargo test --features header-value + - name: Test (strict-header-value) + run: cargo test --features strict-header-value - name: Bench run: cargo bench - - name: Bench (header-value) - run: cargo bench --features header-value + - name: Bench (strict-header-value) + run: cargo bench --features strict-header-value - name: Format (rustfmt) run: cargo fmt -- --check diff --git a/BUILD b/BUILD index eb96231e..6ceeb493 100644 --- a/BUILD +++ b/BUILD @@ -40,9 +40,9 @@ rust_library( ) rust_library( - name = "proxy_wasm_header_value", + name = "proxy_wasm_strict_header_value", srcs = glob(["src/*.rs"]), - crate_features = ["header-value"], + crate_features = ["strict-header-value"], crate_name = "proxy_wasm", edition = "2018", visibility = ["//visibility:public"], @@ -78,7 +78,7 @@ rust_binary( rustc_flags = ["-Cstrip=debuginfo"], visibility = ["//visibility:private"], deps = [ - ":proxy_wasm_header_value", + ":proxy_wasm_strict_header_value", "//bazel/cargo/remote:log", ], ) diff --git a/Cargo.toml b/Cargo.toml index ea592ce8..3ef19038 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ log = "0.4" [features] default = [] -header-value = ["dep:bytes", "dep:http"] +strict-header-value = ["dep:bytes", "dep:http"] [profile.release] lto = true diff --git a/README.md b/README.md index 9b29505c..5cc30733 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This crate supports the following optional features: -- `header-value` - uses RFC-compliant `HeaderValue` instead of UTF-8 `String` for HTTP header and trailer values. +- `strict-header-value` - uses RFC-compliant `HeaderValue` instead of UTF-8 `String` for HTTP header and trailer values. This will become the default in future releases. ## Examples diff --git a/examples/grpc_auth_random/Cargo.toml b/examples/grpc_auth_random/Cargo.toml index 3e5b3be6..6728cb71 100644 --- a/examples/grpc_auth_random/Cargo.toml +++ b/examples/grpc_auth_random/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib"] [dependencies] log = "0.4" -proxy-wasm = { path = "../../", features = ["header-value"] } +proxy-wasm = { path = "../../", features = ["strict-header-value"] } [profile.release] lto = true diff --git a/examples/http_headers/Cargo.toml b/examples/http_headers/Cargo.toml index 2fb8fa6a..d98cdb66 100644 --- a/examples/http_headers/Cargo.toml +++ b/examples/http_headers/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["cdylib"] [dependencies] log = "0.4" -proxy-wasm = { path = "../../", features = ["header-value"] } +proxy-wasm = { path = "../../", features = ["strict-header-value"] } [profile.release] lto = true diff --git a/src/hostcalls.rs b/src/hostcalls.rs index a187b4cc..e5f0cea7 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -145,7 +145,7 @@ extern "C" { ) -> Status; } -#[cfg(feature = "header-value")] +#[cfg(feature = "strict-header-value")] pub fn get_map(map_type: MapType) -> Result, Status> { unsafe { let mut return_data: *mut u8 = null_mut(); @@ -165,7 +165,7 @@ pub fn get_map(map_type: MapType) -> Result, Status> } } -#[cfg(not(feature = "header-value"))] +#[cfg(not(feature = "strict-header-value"))] pub fn get_map(map_type: MapType) -> Result, Status> { unsafe { let mut return_data: *mut u8 = null_mut(); @@ -237,7 +237,7 @@ extern "C" { ) -> Status; } -#[cfg(feature = "header-value")] +#[cfg(feature = "strict-header-value")] pub fn get_map_value(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; @@ -268,7 +268,7 @@ pub fn get_map_value(map_type: MapType, key: &str) -> Result } } -#[cfg(not(feature = "header-value"))] +#[cfg(not(feature = "strict-header-value"))] pub fn get_map_value(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; @@ -1182,9 +1182,9 @@ pub fn increment_metric(metric_id: u32, offset: i64) -> Result<(), Status> { mod utils { use crate::types::Bytes; - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] use crate::types::HeaderValue; - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] use bytes::Buf; use std::convert::TryFrom; @@ -1232,7 +1232,7 @@ mod utils { serialize_map(map) } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] pub(super) fn deserialize_map(mut bytes: bytes::Bytes) -> Vec<(String, HeaderValue)> { if bytes.is_empty() { return Vec::new(); @@ -1258,7 +1258,7 @@ mod utils { map } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] pub(super) fn deserialize_map(bytes: &[u8]) -> Vec<(String, String)> { if bytes.is_empty() { return Vec::new(); @@ -1440,7 +1440,7 @@ mod utils { assert_eq!(serialized_map, SERIALIZED_MAP); } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] #[test] fn test_deserialize_map_all_chars() { // We're intentionally accepting all values to support hosts and proxies that @@ -1456,7 +1456,7 @@ mod utils { } } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] #[test] fn test_deserialize_map_all_chars() { // 0x00-0x7f are valid single-byte UTF-8 characters. @@ -1513,7 +1513,7 @@ mod utils { }); } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] #[cfg(nightly)] #[bench] fn bench_deserialize_map(b: &mut Bencher) { @@ -1523,7 +1523,7 @@ mod utils { }); } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] #[cfg(nightly)] #[bench] fn bench_deserialize_map(b: &mut Bencher) { diff --git a/src/traits.rs b/src/traits.rs index 2724297e..21980da1 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -62,7 +62,7 @@ pub trait Context { hostcalls::enqueue_shared_queue(queue_id, value) } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn dispatch_http_call( &self, upstream: &str, @@ -74,7 +74,7 @@ pub trait Context { hostcalls::dispatch_http_call(upstream, headers, body, trailers, timeout) } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn dispatch_http_call( &self, upstream: &str, @@ -95,12 +95,12 @@ pub trait Context { ) { } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_call_response_headers(&self) -> Vec<(String, HeaderValue)> { hostcalls::get_map(MapType::HttpCallResponseHeaders).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_call_response_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpCallResponseHeaders).unwrap() } @@ -109,12 +109,12 @@ pub trait Context { hostcalls::get_map_bytes(MapType::HttpCallResponseHeaders).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_call_response_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_call_response_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseHeaders, name).unwrap() } @@ -127,12 +127,12 @@ pub trait Context { hostcalls::get_buffer(BufferType::HttpCallResponseBody, start, max_size).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_call_response_trailers(&self) -> Vec<(String, HeaderValue)> { hostcalls::get_map(MapType::HttpCallResponseTrailers).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_call_response_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpCallResponseTrailers).unwrap() } @@ -141,12 +141,12 @@ pub trait Context { hostcalls::get_map_bytes(MapType::HttpCallResponseTrailers).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_call_response_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_call_response_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() } @@ -354,12 +354,12 @@ pub trait HttpContext: Context { Action::Continue } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_request_headers(&self) -> Vec<(String, HeaderValue)> { hostcalls::get_map(MapType::HttpRequestHeaders).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_request_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestHeaders).unwrap() } @@ -368,12 +368,12 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpRequestHeaders).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn set_http_request_headers(&self, headers: Vec<(&str, &HeaderValue)>) { hostcalls::set_map(MapType::HttpRequestHeaders, headers).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn set_http_request_headers(&self, headers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpRequestHeaders, headers).unwrap() } @@ -382,12 +382,12 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpRequestHeaders, headers).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_request_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestHeaders, name).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_request_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestHeaders, name).unwrap() } @@ -396,12 +396,12 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpRequestHeaders, name).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn set_http_request_header(&self, name: &str, value: Option<&HeaderValue>) { hostcalls::set_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn set_http_request_header(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } @@ -410,12 +410,12 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpRequestHeaders, name, value).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn add_http_request_header(&self, name: &str, value: &HeaderValue) { hostcalls::add_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn add_http_request_header(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } @@ -444,12 +444,12 @@ pub trait HttpContext: Context { Action::Continue } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_request_trailers(&self) -> Vec<(String, HeaderValue)> { hostcalls::get_map(MapType::HttpRequestTrailers).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_request_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestTrailers).unwrap() } @@ -458,12 +458,12 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpRequestTrailers).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn set_http_request_trailers(&self, trailers: Vec<(&str, &HeaderValue)>) { hostcalls::set_map(MapType::HttpRequestTrailers, trailers).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn set_http_request_trailers(&self, trailers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpRequestTrailers, trailers).unwrap() } @@ -472,12 +472,12 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpRequestTrailers, trailers).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_request_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestTrailers, name).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_request_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestTrailers, name).unwrap() } @@ -486,12 +486,12 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpRequestTrailers, name).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn set_http_request_trailer(&self, name: &str, value: Option<&HeaderValue>) { hostcalls::set_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn set_http_request_trailer(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } @@ -500,12 +500,12 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpRequestTrailers, name, value).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn add_http_request_trailer(&self, name: &str, value: &HeaderValue) { hostcalls::add_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn add_http_request_trailer(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } @@ -530,12 +530,12 @@ pub trait HttpContext: Context { Action::Continue } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_response_headers(&self) -> Vec<(String, HeaderValue)> { hostcalls::get_map(MapType::HttpResponseHeaders).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_response_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseHeaders).unwrap() } @@ -544,12 +544,12 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpResponseHeaders).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn set_http_response_headers(&self, headers: Vec<(&str, &HeaderValue)>) { hostcalls::set_map(MapType::HttpResponseHeaders, headers).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn set_http_response_headers(&self, headers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpResponseHeaders, headers).unwrap() } @@ -558,12 +558,12 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpResponseHeaders, headers).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_response_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseHeaders, name).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_response_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseHeaders, name).unwrap() } @@ -572,12 +572,12 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpResponseHeaders, name).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn set_http_response_header(&self, name: &str, value: Option<&HeaderValue>) { hostcalls::set_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn set_http_response_header(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } @@ -586,12 +586,12 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpResponseHeaders, name, value).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn add_http_response_header(&self, name: &str, value: &HeaderValue) { hostcalls::add_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn add_http_response_header(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } @@ -620,12 +620,12 @@ pub trait HttpContext: Context { Action::Continue } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_response_trailers(&self) -> Vec<(String, HeaderValue)> { hostcalls::get_map(MapType::HttpResponseTrailers).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_response_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseTrailers).unwrap() } @@ -634,12 +634,12 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpResponseTrailers).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn set_http_response_trailers(&self, trailers: Vec<(&str, &HeaderValue)>) { hostcalls::set_map(MapType::HttpResponseTrailers, trailers).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn set_http_response_trailers(&self, trailers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpResponseTrailers, trailers).unwrap() } @@ -648,12 +648,12 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpResponseTrailers, trailers).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn get_http_response_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseTrailers, name).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn get_http_response_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseTrailers, name).unwrap() } @@ -662,12 +662,12 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpResponseTrailers, name).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn set_http_response_trailer(&self, name: &str, value: Option<&HeaderValue>) { hostcalls::set_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn set_http_response_trailer(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } @@ -676,12 +676,12 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpResponseTrailers, name, value).unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn add_http_response_trailer(&self, name: &str, value: &HeaderValue) { hostcalls::add_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn add_http_response_trailer(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } @@ -702,7 +702,7 @@ pub trait HttpContext: Context { hostcalls::reset_http_response().unwrap() } - #[cfg(feature = "header-value")] + #[cfg(feature = "strict-header-value")] fn send_http_response( &self, status_code: u32, @@ -712,7 +712,7 @@ pub trait HttpContext: Context { hostcalls::send_http_response(status_code, headers, body).unwrap() } - #[cfg(not(feature = "header-value"))] + #[cfg(not(feature = "strict-header-value"))] fn send_http_response( &self, status_code: u32, diff --git a/src/types.rs b/src/types.rs index a8e78f61..16cb5621 100644 --- a/src/types.rs +++ b/src/types.rs @@ -141,5 +141,5 @@ pub enum GrpcStatusCode { pub type Bytes = Vec; -#[cfg(feature = "header-value")] +#[cfg(feature = "strict-header-value")] pub use http::HeaderValue; From 1155a99736f673a905f50e505c7d9cb30b07ada4 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 24 Jan 2026 21:15:04 -0500 Subject: [PATCH 06/17] review: update Bazel dependencies. Signed-off-by: Piotr Sikora --- MODULE.bazel | 4 +- bazel/cargo/Cargo.Bazel.lock | 19 ++-- bazel/cargo/remote/BUILD.bazel | 12 +-- ...-1.10.1.bazel => BUILD.bytes-1.11.0.bazel} | 4 +- bazel/cargo/remote/BUILD.fnv-1.0.7.bazel | 100 ------------------ ...ttp-1.3.1.bazel => BUILD.http-1.4.0.bazel} | 9 +- ...a-1.0.15.bazel => BUILD.itoa-1.0.17.bazel} | 4 +- bazel/cargo/remote/defs.bzl | 48 ++++----- 8 files changed, 41 insertions(+), 159 deletions(-) rename bazel/cargo/remote/{BUILD.bytes-1.10.1.bazel => BUILD.bytes-1.11.0.bazel} (98%) delete mode 100644 bazel/cargo/remote/BUILD.fnv-1.0.7.bazel rename bazel/cargo/remote/{BUILD.http-1.3.1.bazel => BUILD.http-1.4.0.bazel} (95%) rename bazel/cargo/remote/{BUILD.itoa-1.0.15.bazel => BUILD.itoa-1.0.17.bazel} (98%) diff --git a/MODULE.bazel b/MODULE.bazel index 6beb2bd0..88a36708 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -51,8 +51,8 @@ crates_deps = use_extension("//bazel:extensions.bzl", "crates_deps") use_repo( crates_deps, "crates_vendor", - "crates_vendor__bytes-1.10.1", + "crates_vendor__bytes-1.11.0", "crates_vendor__hashbrown-0.16.0", - "crates_vendor__http-1.3.1", + "crates_vendor__http-1.4.0", "crates_vendor__log-0.4.27", ) diff --git a/bazel/cargo/Cargo.Bazel.lock b/bazel/cargo/Cargo.Bazel.lock index dac108f1..de93b60e 100644 --- a/bazel/cargo/Cargo.Bazel.lock +++ b/bazel/cargo/Cargo.Bazel.lock @@ -10,9 +10,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "equivalent" @@ -20,12 +20,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "foldhash" version = "0.2.0" @@ -45,20 +39,19 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "log" diff --git a/bazel/cargo/remote/BUILD.bazel b/bazel/cargo/remote/BUILD.bazel index 998612cf..3a16db1c 100644 --- a/bazel/cargo/remote/BUILD.bazel +++ b/bazel/cargo/remote/BUILD.bazel @@ -32,14 +32,14 @@ filegroup( # Workspace Member Dependencies alias( - name = "bytes-1.10.1", - actual = "@crates_vendor__bytes-1.10.1//:bytes", + name = "bytes-1.11.0", + actual = "@crates_vendor__bytes-1.11.0//:bytes", tags = ["manual"], ) alias( name = "bytes", - actual = "@crates_vendor__bytes-1.10.1//:bytes", + actual = "@crates_vendor__bytes-1.11.0//:bytes", tags = ["manual"], ) @@ -56,14 +56,14 @@ alias( ) alias( - name = "http-1.3.1", - actual = "@crates_vendor__http-1.3.1//:http", + name = "http-1.4.0", + actual = "@crates_vendor__http-1.4.0//:http", tags = ["manual"], ) alias( name = "http", - actual = "@crates_vendor__http-1.3.1//:http", + actual = "@crates_vendor__http-1.4.0//:http", tags = ["manual"], ) diff --git a/bazel/cargo/remote/BUILD.bytes-1.10.1.bazel b/bazel/cargo/remote/BUILD.bytes-1.11.0.bazel similarity index 98% rename from bazel/cargo/remote/BUILD.bytes-1.10.1.bazel rename to bazel/cargo/remote/BUILD.bytes-1.11.0.bazel index 8ea1270f..016a6df8 100644 --- a/bazel/cargo/remote/BUILD.bytes-1.10.1.bazel +++ b/bazel/cargo/remote/BUILD.bytes-1.11.0.bazel @@ -39,7 +39,7 @@ rust_library( "std", ], crate_root = "src/lib.rs", - edition = "2018", + edition = "2021", rustc_env_files = [ ":cargo_toml_env_vars", ], @@ -96,5 +96,5 @@ rust_library( "@rules_rust//rust/platform:x86_64-unknown-uefi": [], "//conditions:default": ["@platforms//:incompatible"], }), - version = "1.10.1", + version = "1.11.0", ) diff --git a/bazel/cargo/remote/BUILD.fnv-1.0.7.bazel b/bazel/cargo/remote/BUILD.fnv-1.0.7.bazel deleted file mode 100644 index 479561b6..00000000 --- a/bazel/cargo/remote/BUILD.fnv-1.0.7.bazel +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @//bazel/cargo:crates_vendor -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "fnv", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "std", - ], - crate_root = "lib.rs", - edition = "2015", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=fnv", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "1.0.7", -) diff --git a/bazel/cargo/remote/BUILD.http-1.3.1.bazel b/bazel/cargo/remote/BUILD.http-1.4.0.bazel similarity index 95% rename from bazel/cargo/remote/BUILD.http-1.3.1.bazel rename to bazel/cargo/remote/BUILD.http-1.4.0.bazel index 898d3915..52375ecd 100644 --- a/bazel/cargo/remote/BUILD.http-1.3.1.bazel +++ b/bazel/cargo/remote/BUILD.http-1.4.0.bazel @@ -39,7 +39,7 @@ rust_library( "std", ], crate_root = "src/lib.rs", - edition = "2018", + edition = "2021", rustc_env_files = [ ":cargo_toml_env_vars", ], @@ -96,10 +96,9 @@ rust_library( "@rules_rust//rust/platform:x86_64-unknown-uefi": [], "//conditions:default": ["@platforms//:incompatible"], }), - version = "1.3.1", + version = "1.4.0", deps = [ - "@crates_vendor__bytes-1.10.1//:bytes", - "@crates_vendor__fnv-1.0.7//:fnv", - "@crates_vendor__itoa-1.0.15//:itoa", + "@crates_vendor__bytes-1.11.0//:bytes", + "@crates_vendor__itoa-1.0.17//:itoa", ], ) diff --git a/bazel/cargo/remote/BUILD.itoa-1.0.15.bazel b/bazel/cargo/remote/BUILD.itoa-1.0.17.bazel similarity index 98% rename from bazel/cargo/remote/BUILD.itoa-1.0.15.bazel rename to bazel/cargo/remote/BUILD.itoa-1.0.17.bazel index b9ad55cf..4748cb99 100644 --- a/bazel/cargo/remote/BUILD.itoa-1.0.15.bazel +++ b/bazel/cargo/remote/BUILD.itoa-1.0.17.bazel @@ -35,7 +35,7 @@ rust_library( ], ), crate_root = "src/lib.rs", - edition = "2018", + edition = "2021", rustc_env_files = [ ":cargo_toml_env_vars", ], @@ -92,5 +92,5 @@ rust_library( "@rules_rust//rust/platform:x86_64-unknown-uefi": [], "//conditions:default": ["@platforms//:incompatible"], }), - version = "1.0.15", + version = "1.0.17", ) diff --git a/bazel/cargo/remote/defs.bzl b/bazel/cargo/remote/defs.bzl index 3ee3a381..215d5721 100644 --- a/bazel/cargo/remote/defs.bzl +++ b/bazel/cargo/remote/defs.bzl @@ -295,9 +295,9 @@ def aliases( _NORMAL_DEPENDENCIES = { "": { _COMMON_CONDITION: { - "bytes": Label("@crates_vendor//:bytes-1.10.1"), + "bytes": Label("@crates_vendor//:bytes-1.11.0"), "hashbrown": Label("@crates_vendor//:hashbrown-0.16.0"), - "http": Label("@crates_vendor//:http-1.3.1"), + "http": Label("@crates_vendor//:http-1.4.0"), "log": Label("@crates_vendor//:log-0.4.27"), }, }, @@ -430,12 +430,12 @@ def crate_repositories(): maybe( http_archive, - name = "crates_vendor__bytes-1.10.1", - sha256 = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a", + name = "crates_vendor__bytes-1.11.0", + sha256 = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3", type = "tar.gz", - urls = ["https://static.crates.io/crates/bytes/1.10.1/download"], - strip_prefix = "bytes-1.10.1", - build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.bytes-1.10.1.bazel"), + urls = ["https://static.crates.io/crates/bytes/1.11.0/download"], + strip_prefix = "bytes-1.11.0", + build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.bytes-1.11.0.bazel"), ) maybe( @@ -448,16 +448,6 @@ def crate_repositories(): build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.equivalent-1.0.2.bazel"), ) - maybe( - http_archive, - name = "crates_vendor__fnv-1.0.7", - sha256 = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1", - type = "tar.gz", - urls = ["https://static.crates.io/crates/fnv/1.0.7/download"], - strip_prefix = "fnv-1.0.7", - build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.fnv-1.0.7.bazel"), - ) - maybe( http_archive, name = "crates_vendor__foldhash-0.2.0", @@ -480,22 +470,22 @@ def crate_repositories(): maybe( http_archive, - name = "crates_vendor__http-1.3.1", - sha256 = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565", + name = "crates_vendor__http-1.4.0", + sha256 = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a", type = "tar.gz", - urls = ["https://static.crates.io/crates/http/1.3.1/download"], - strip_prefix = "http-1.3.1", - build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.http-1.3.1.bazel"), + urls = ["https://static.crates.io/crates/http/1.4.0/download"], + strip_prefix = "http-1.4.0", + build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.http-1.4.0.bazel"), ) maybe( http_archive, - name = "crates_vendor__itoa-1.0.15", - sha256 = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c", + name = "crates_vendor__itoa-1.0.17", + sha256 = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2", type = "tar.gz", - urls = ["https://static.crates.io/crates/itoa/1.0.15/download"], - strip_prefix = "itoa-1.0.15", - build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.itoa-1.0.15.bazel"), + urls = ["https://static.crates.io/crates/itoa/1.0.17/download"], + strip_prefix = "itoa-1.0.17", + build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.itoa-1.0.17.bazel"), ) maybe( @@ -569,9 +559,9 @@ def crate_repositories(): ) return [ - struct(repo = "crates_vendor__bytes-1.10.1", is_dev_dep = False), + struct(repo = "crates_vendor__bytes-1.11.0", is_dev_dep = False), struct(repo = "crates_vendor__hashbrown-0.16.0", is_dev_dep = False), - struct(repo = "crates_vendor__http-1.3.1", is_dev_dep = False), + struct(repo = "crates_vendor__http-1.4.0", is_dev_dep = False), struct(repo = "crates_vendor__log-0.4.27", is_dev_dep = False), struct(repo = "crates_vendor__mockalloc-0.1.2", is_dev_dep = True), ] From a64ab45dba4932dc6bd85d488a44236099f3dc2c Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 24 Jan 2026 21:22:58 -0500 Subject: [PATCH 07/17] review: fix memory leaks and add more alloc tests. Signed-off-by: Piotr Sikora --- src/hostcalls.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/src/hostcalls.rs b/src/hostcalls.rs index 0275aa43..34c682a1 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -163,8 +163,11 @@ pub fn get_map(map_type: MapType) -> Result, Status> match proxy_get_header_map_pairs(map_type, &mut return_data, &mut return_size) { Status::Ok => { if !return_data.is_null() { - let serialized_map = - bytes::Bytes::from(std::slice::from_raw_parts(return_data, return_size)); + let serialized_map = bytes::Bytes::from(Vec::from_raw_parts( + return_data, + return_size, + return_size, + )); Ok(utils::deserialize_map(serialized_map)) } else { Ok(Vec::new()) @@ -237,6 +240,7 @@ pub fn set_map_bytes(map_type: MapType, map: Vec<(&str, &[u8])>) -> Result<(), S set_map(map_type, map) } +#[cfg(not(test))] extern "C" { fn proxy_get_header_map_value( map_type: MapType, @@ -247,6 +251,23 @@ extern "C" { ) -> Status; } +#[cfg(test)] +fn proxy_get_header_map_value( + map_type: MapType, + key_data: *const u8, + key_size: usize, + return_value_data: *mut *mut u8, + return_value_size: *mut usize, +) -> Status { + mocks::proxy_get_header_map_value( + map_type, + key_data, + key_size, + return_value_data, + return_value_size, + ) +} + #[cfg(feature = "strict-header-value")] pub fn get_map_value(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); @@ -261,9 +282,10 @@ pub fn get_map_value(map_type: MapType, key: &str) -> Result ) { Status::Ok => { if !return_data.is_null() { - match HeaderValue::from_bytes(std::slice::from_raw_parts( + match HeaderValue::from_maybe_shared(Vec::from_raw_parts( return_data, return_size, + return_size, )) { Ok(value) => Ok(Some(value)), Err(_) => panic!("invalid field value in: {}", key), @@ -1213,6 +1235,24 @@ mod mocks { } Status::Ok } + + pub fn proxy_get_header_map_value( + _map_type: MapType, + _key_data: *const u8, + _key_size: usize, + return_value_data: *mut *mut u8, + return_value_size: *mut usize, + ) -> Status { + let mut value = String::from("foo"); + value.push_str("-prevent-optimizations"); + let layout = Layout::array::(value.len()).unwrap(); + unsafe { + *return_value_data = alloc(layout); + *return_value_size = value.len(); + std::ptr::copy(value.as_ptr(), *return_value_data, value.len()); + } + Status::Ok + } } #[cfg(test)] @@ -1235,6 +1275,18 @@ mod tests { let result = super::get_map_bytes(MapType::HttpRequestHeaders); assert!(result.is_ok()); } + + #[mockalloc::test] + fn test_get_map_value_no_leaks() { + let result = super::get_map_value(MapType::HttpRequestHeaders, "foo"); + assert!(result.is_ok()); + } + + #[mockalloc::test] + fn test_get_map_value_bytes_no_leaks() { + let result = super::get_map_value_bytes(MapType::HttpRequestHeaders, "foo"); + assert!(result.is_ok()); + } } mod utils { From c5ed28d88fa53da996ff0d611b2bcb5a6aa1718a Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 24 Jan 2026 21:26:24 -0500 Subject: [PATCH 08/17] review: migrate from Cargo feature to _typed() suffix. Signed-off-by: Piotr Sikora --- .github/workflows/rust.yml | 32 ------ BUILD | 28 ----- Cargo.toml | 8 +- README.md | 7 -- examples/grpc_auth_random/Cargo.toml | 2 +- examples/grpc_auth_random/src/lib.rs | 8 +- examples/http_headers/Cargo.toml | 2 +- examples/http_headers/src/lib.rs | 6 +- src/hostcalls.rs | 158 ++++++++++++++++++++------- src/traits.rs | 152 +++++++++----------------- src/types.rs | 1 - 11 files changed, 179 insertions(+), 225 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 43503115..4ec8dc5c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -102,9 +102,7 @@ jobs: - name: Format (rules_rust) run: | - sed -i'' -E 's/^default = \[\]/default = \[\"strict-header-value\"\]/' Cargo.toml bazelisk --noworkspace_rc run --noenable_bzlmod //bazel/cargo:crates_vendor - git checkout Cargo.toml git diff --exit-code - name: Format (MODULE.bazel.lock) @@ -161,18 +159,9 @@ jobs: - name: Clippy (wasm32-wasi) run: cargo clippy --release --all-targets --target=wasm32-wasi - - name: Build (strict-header-value) - run: cargo build --release --all-targets --target=wasm32-wasi --features strict-header-value - - - name: Clippy (strict-header-value) - run: cargo clippy --release --all-targets --target=wasm32-wasi --features strict-header-value - - name: Test run: cargo test - - name: Test (strict-header-value) - run: cargo test --features strict-header-value - - name: Format (rustfmt) run: cargo fmt -- --check @@ -235,18 +224,9 @@ jobs: - name: Clippy (wasm32-wasip1) run: cargo clippy --release --all-targets --target=wasm32-wasip1 - - name: Build (strict-header-value) - run: cargo build --release --all-targets --target=wasm32-wasip1 --features strict-header-value - - - name: Clippy (strict-header-value) - run: cargo clippy --release --all-targets --target=wasm32-wasip1 --features strict-header-value - - name: Test run: cargo test - - name: Test (strict-header-value) - run: cargo test --features strict-header-value - - name: Format (rustfmt) run: cargo fmt -- --check @@ -310,24 +290,12 @@ jobs: - name: Clippy (wasm32-wasip1) run: cargo clippy --release --all-targets --target=wasm32-wasip1 - - name: Build (strict-header-value) - run: cargo build --release --all-targets --target=wasm32-wasip1 --features strict-header-value - - - name: Clippy (strict-header-value) - run: cargo clippy --release --all-targets --target=wasm32-wasip1 --features strict-header-value - - name: Test run: cargo test - - name: Test (strict-header-value) - run: cargo test --features strict-header-value - - name: Bench run: cargo bench - - name: Bench (strict-header-value) - run: cargo bench --features strict-header-value - - name: Format (rustfmt) run: cargo fmt -- --check diff --git a/BUILD b/BUILD index 6ceeb493..f8b02ffb 100644 --- a/BUILD +++ b/BUILD @@ -32,20 +32,6 @@ rust_library( srcs = glob(["src/*.rs"]), edition = "2018", visibility = ["//visibility:public"], - deps = [ - ":proxy_wasm_build_script", - "//bazel/cargo/remote:hashbrown", - "//bazel/cargo/remote:log", - ], -) - -rust_library( - name = "proxy_wasm_strict_header_value", - srcs = glob(["src/*.rs"]), - crate_features = ["strict-header-value"], - crate_name = "proxy_wasm", - edition = "2018", - visibility = ["//visibility:public"], deps = [ ":proxy_wasm_build_script", "//bazel/cargo/remote:bytes", @@ -68,17 +54,3 @@ rust_binary( "//bazel/cargo/remote:log", ], ) - -rust_binary( - name = "grpc_auth_random", - srcs = ["examples/grpc_auth_random/src/lib.rs"], - crate_type = "cdylib", - edition = "2018", - out_binary = True, - rustc_flags = ["-Cstrip=debuginfo"], - visibility = ["//visibility:private"], - deps = [ - ":proxy_wasm_strict_header_value", - "//bazel/cargo/remote:log", - ], -) diff --git a/Cargo.toml b/Cargo.toml index 8a6a3ffd..1238e9e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,18 +11,14 @@ edition = "2018" build = "build.rs" [dependencies] -bytes = { version = "1", optional = true } +bytes = "1" hashbrown = "0.16" -http = { version = "1", optional = true } +http = "1" log = "0.4" [dev-dependencies] mockalloc = "0.1.2" -[features] -default = [] -strict-header-value = ["dep:bytes", "dep:http"] - [profile.release] lto = true opt-level = 3 diff --git a/README.md b/README.md index 5cc30733..fa53c221 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,6 @@ [license-badge]: https://img.shields.io/github/license/proxy-wasm/proxy-wasm-rust-sdk [license-link]: https://github.com/proxy-wasm/proxy-wasm-rust-sdk/blob/main/LICENSE -## Crate features - -This crate supports the following optional features: - -- `strict-header-value` - uses RFC-compliant `HeaderValue` instead of UTF-8 `String` for HTTP header and trailer values. - This will become the default in future releases. - ## Examples - [Hello World](./examples/hello_world/) diff --git a/examples/grpc_auth_random/Cargo.toml b/examples/grpc_auth_random/Cargo.toml index 6728cb71..c3e6ec01 100644 --- a/examples/grpc_auth_random/Cargo.toml +++ b/examples/grpc_auth_random/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib"] [dependencies] log = "0.4" -proxy-wasm = { path = "../../", features = ["strict-header-value"] } +proxy-wasm = { path = "../../" } [profile.release] lto = true diff --git a/examples/grpc_auth_random/src/lib.rs b/examples/grpc_auth_random/src/lib.rs index eef44e51..cc7c79b0 100644 --- a/examples/grpc_auth_random/src/lib.rs +++ b/examples/grpc_auth_random/src/lib.rs @@ -26,11 +26,11 @@ struct GrpcAuthRandom; impl HttpContext for GrpcAuthRandom { fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action { - match self.get_http_request_header("content-type") { + match self.get_http_request_header_typed("content-type") { Some(value) if value.as_bytes().starts_with(b"application/grpc") => {} _ => { // Reject non-gRPC clients. - self.send_http_response( + self.send_http_response_typed( 503, vec![("Powered-By", &HeaderValue::from_static("proxy-wasm"))], Some(b"Service accessible only to gRPC clients.\n"), @@ -39,7 +39,7 @@ impl HttpContext for GrpcAuthRandom { } } - match self.get_http_request_header(":path") { + match self.get_http_request_header_typed(":path") { Some(value) if value.as_bytes().starts_with(b"/grpc.reflection") => { // Always allow gRPC calls to the reflection API. Action::Continue @@ -61,7 +61,7 @@ impl HttpContext for GrpcAuthRandom { } fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action { - self.set_http_response_header("Powered-By", Some(&HeaderValue::from_static("proxy-wasm"))); + self.set_http_response_header_typed("Powered-By", Some(&HeaderValue::from_static("proxy-wasm"))); Action::Continue } } diff --git a/examples/http_headers/Cargo.toml b/examples/http_headers/Cargo.toml index d98cdb66..02afd242 100644 --- a/examples/http_headers/Cargo.toml +++ b/examples/http_headers/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["cdylib"] [dependencies] log = "0.4" -proxy-wasm = { path = "../../", features = ["strict-header-value"] } +proxy-wasm = { path = "../../" } [profile.release] lto = true diff --git a/examples/http_headers/src/lib.rs b/examples/http_headers/src/lib.rs index a6a4942b..76cacff5 100644 --- a/examples/http_headers/src/lib.rs +++ b/examples/http_headers/src/lib.rs @@ -43,7 +43,7 @@ impl Context for HttpHeaders {} impl HttpContext for HttpHeaders { fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action { - for (name, value) in &self.get_http_request_headers() { + for (name, value) in &self.get_http_request_headers_typed() { info!( "#{} -> {}: {}", self.context_id, @@ -54,7 +54,7 @@ impl HttpContext for HttpHeaders { match self.get_http_request_header(":path") { Some(path) if path == "/hello" => { - self.send_http_response( + self.send_http_response_typed( 200, vec![ ("Hello", &HeaderValue::from_static("World")), @@ -69,7 +69,7 @@ impl HttpContext for HttpHeaders { } fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action { - for (name, value) in &self.get_http_response_headers() { + for (name, value) in &self.get_http_response_headers_typed() { info!( "#{} <- {}: {}", self.context_id, diff --git a/src/hostcalls.rs b/src/hostcalls.rs index 34c682a1..4f91d167 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -155,8 +155,7 @@ fn proxy_get_header_map_pairs( mocks::proxy_get_header_map_pairs(map_type, return_map_data, return_map_size) } -#[cfg(feature = "strict-header-value")] -pub fn get_map(map_type: MapType) -> Result, Status> { +pub fn get_map_typed(map_type: MapType) -> Result, Status> { unsafe { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; @@ -168,7 +167,7 @@ pub fn get_map(map_type: MapType) -> Result, Status> return_size, return_size, )); - Ok(utils::deserialize_map(serialized_map)) + Ok(utils::deserialize_map_typed(serialized_map)) } else { Ok(Vec::new()) } @@ -178,7 +177,6 @@ pub fn get_map(map_type: MapType) -> Result, Status> } } -#[cfg(not(feature = "strict-header-value"))] pub fn get_map(map_type: MapType) -> Result, Status> { unsafe { let mut return_data: *mut u8 = null_mut(); @@ -240,6 +238,10 @@ pub fn set_map_bytes(map_type: MapType, map: Vec<(&str, &[u8])>) -> Result<(), S set_map(map_type, map) } +pub fn set_map_typed(map_type: MapType, map: Vec<(&str, &HeaderValue)>) -> Result<(), Status> { + set_map(map_type, map) +} + #[cfg(not(test))] extern "C" { fn proxy_get_header_map_value( @@ -268,8 +270,7 @@ fn proxy_get_header_map_value( ) } -#[cfg(feature = "strict-header-value")] -pub fn get_map_value(map_type: MapType, key: &str) -> Result, Status> { +pub fn get_map_value_typed(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; unsafe { @@ -300,7 +301,6 @@ pub fn get_map_value(map_type: MapType, key: &str) -> Result } } -#[cfg(not(feature = "strict-header-value"))] pub fn get_map_value(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; @@ -420,6 +420,14 @@ pub fn set_map_value_bytes( set_map_value(map_type, key, value) } +pub fn set_map_value_typed( + map_type: MapType, + key: &str, + value: Option<&HeaderValue>, +) -> Result<(), Status> { + set_map_value(map_type, key, value) +} + extern "C" { fn proxy_add_header_map_value( map_type: MapType, @@ -452,6 +460,14 @@ pub fn add_map_value_bytes(map_type: MapType, key: &str, value: &[u8]) -> Result add_map_value(map_type, key, value) } +pub fn add_map_value_typed( + map_type: MapType, + key: &str, + value: &HeaderValue, +) -> Result<(), Status> { + add_map_value(map_type, key, value) +} + extern "C" { fn proxy_get_property( path_data: *const u8, @@ -1276,6 +1292,12 @@ mod tests { assert!(result.is_ok()); } + #[mockalloc::test] + fn test_get_map_typed_no_leaks() { + let result = super::get_map_typed(MapType::HttpRequestHeaders); + assert!(result.is_ok()); + } + #[mockalloc::test] fn test_get_map_value_no_leaks() { let result = super::get_map_value(MapType::HttpRequestHeaders, "foo"); @@ -1287,13 +1309,17 @@ mod tests { let result = super::get_map_value_bytes(MapType::HttpRequestHeaders, "foo"); assert!(result.is_ok()); } + + #[mockalloc::test] + fn test_get_map_value_typed_no_leaks() { + let result = super::get_map_value_typed(MapType::HttpRequestHeaders, "foo"); + assert!(result.is_ok()); + } } mod utils { use crate::types::Bytes; - #[cfg(feature = "strict-header-value")] use crate::types::HeaderValue; - #[cfg(feature = "strict-header-value")] use bytes::Buf; use std::convert::TryFrom; @@ -1341,8 +1367,12 @@ mod utils { serialize_map(map) } - #[cfg(feature = "strict-header-value")] - pub(super) fn deserialize_map(mut bytes: bytes::Bytes) -> Vec<(String, HeaderValue)> { + #[cfg(test)] + pub(super) fn serialize_map_typed(map: &[(&str, &HeaderValue)]) -> Bytes { + serialize_map(map) + } + + pub(super) fn deserialize_map_typed(mut bytes: bytes::Bytes) -> Vec<(String, HeaderValue)> { if bytes.is_empty() { return Vec::new(); } @@ -1367,7 +1397,6 @@ mod utils { map } - #[cfg(not(feature = "strict-header-value"))] pub(super) fn deserialize_map(bytes: &[u8]) -> Vec<(String, String)> { if bytes.is_empty() { return Vec::new(); @@ -1475,14 +1504,17 @@ mod utils { assert_eq!(serialized_map, SERIALIZED_EMPTY_MAP); } + #[test] + fn test_serialize_map_empty_typed() { + let serialized_map = serialize_map_typed(&[]); + assert_eq!(serialized_map, SERIALIZED_EMPTY_MAP); + } + #[test] fn test_deserialize_map_empty() { - let empty_map: &[u8] = &[]; - #[allow(clippy::useless_conversion)] - let map = deserialize_map(empty_map.into()); + let map = deserialize_map(&[]); assert_eq!(map, []); - #[allow(clippy::useless_conversion)] - let map = deserialize_map(SERIALIZED_EMPTY_MAP.into()); + let map = deserialize_map(SERIALIZED_EMPTY_MAP); assert_eq!(map, []); } @@ -1494,6 +1526,14 @@ mod utils { assert_eq!(map, []); } + #[test] + fn test_deserialize_map_empty_typed() { + let map = deserialize_map_typed(bytes::Bytes::new()); + assert_eq!(map, []); + let map = deserialize_map_typed(SERIALIZED_EMPTY_MAP.into()); + assert_eq!(map, []); + } + #[test] fn test_serialize_map() { let serialized_map = serialize_map(MAP); @@ -1507,10 +1547,20 @@ mod utils { assert_eq!(serialized_map, SERIALIZED_MAP); } + #[test] + fn test_serialize_map_typed() { + let map: Vec<(&str, HeaderValue)> = MAP + .iter() + .map(|x| (x.0, HeaderValue::from_static(x.1))) + .collect(); + let map_refs: Vec<(&str, &HeaderValue)> = map.iter().map(|x| (x.0, &x.1)).collect(); + let serialized_map = serialize_map_typed(&map_refs); + assert_eq!(serialized_map, SERIALIZED_MAP); + } + #[test] fn test_deserialize_map() { - #[allow(clippy::useless_conversion)] - let map = deserialize_map(SERIALIZED_MAP.into()); + let map = deserialize_map(SERIALIZED_MAP); assert_eq!(map.len(), MAP.len()); for (got, expected) in map.into_iter().zip(MAP) { assert_eq!(got.0, expected.0); @@ -1528,12 +1578,21 @@ mod utils { } } + #[test] + fn test_deserialize_map_typed() { + let map = deserialize_map_typed(SERIALIZED_MAP.into()); + assert_eq!(map.len(), MAP.len()); + for (got, expected) in map.into_iter().zip(MAP) { + assert_eq!(got.0, expected.0); + assert_eq!(got.1, expected.1); + } + } + #[test] fn test_deserialize_map_roundtrip() { - #[allow(clippy::useless_conversion)] - let map = deserialize_map(SERIALIZED_MAP.into()); + let map = deserialize_map(SERIALIZED_MAP); // TODO(v0.3): fix arguments, so that maps can be reused without conversion. - let map_refs: Vec<(&str, &[u8])> = + let map_refs: Vec<(&str, &str)> = map.iter().map(|x| (x.0.as_ref(), x.1.as_ref())).collect(); let serialized_map = serialize_map(&map_refs); assert_eq!(serialized_map, SERIALIZED_MAP); @@ -1549,29 +1608,37 @@ mod utils { assert_eq!(serialized_map, SERIALIZED_MAP); } - #[cfg(feature = "strict-header-value")] #[test] - fn test_deserialize_map_all_chars() { + fn test_deserialize_map_roundtrip_typed() { + let map = deserialize_map_typed(SERIALIZED_MAP.into()); + // TODO(v0.3): fix arguments, so that maps can be reused without conversion. + let map_refs: Vec<(&str, &HeaderValue)> = + map.iter().map(|x| (x.0.as_ref(), &x.1)).collect(); + let serialized_map = serialize_map_typed(&map_refs); + assert_eq!(serialized_map, SERIALIZED_MAP); + } + + #[test] + fn test_deserialize_map_all_chars_typed() { // We're intentionally accepting all values to support hosts and proxies that // don't enforce strict RFC compliance on HTTP field values. for i in 0..0xff { - let serialized_src: &[u8] = &[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; - let map = deserialize_map(serialized_src.to_vec().into()); + let serialized_src = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; + let map = deserialize_map_typed(serialized_src.to_vec().into()); // TODO(v0.3): fix arguments, so that maps can be reused without conversion. - let map_refs: Vec<(&str, &[u8])> = - map.iter().map(|x| (x.0.as_ref(), x.1.as_ref())).collect(); - let serialized_map = serialize_map(&map_refs); + let map_refs: Vec<(&str, &HeaderValue)> = + map.iter().map(|x| (x.0.as_ref(), &x.1)).collect(); + let serialized_map = serialize_map_typed(&map_refs); assert_eq!(serialized_map, serialized_src); } } - #[cfg(not(feature = "strict-header-value"))] #[test] fn test_deserialize_map_all_chars() { // 0x00-0x7f are valid single-byte UTF-8 characters. for i in 0..0x7f { - let serialized_src: &[u8] = &[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; - let map = deserialize_map(serialized_src); + let serialized_src = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; + let map = deserialize_map(&serialized_src); // TODO(v0.3): fix arguments, so that maps can be reused without conversion. let map_refs: Vec<(&str, &str)> = map.iter().map(|x| (x.0.as_ref(), x.1.as_ref())).collect(); @@ -1580,11 +1647,11 @@ mod utils { } // 0x80-0xff are invalid single-byte UTF-8 characters. for i in 0x80..0xff { - let serialized_src: &[u8] = &[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; + let serialized_src = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; // Override panic to silence panic logs in the test output. std::panic::set_hook(Box::new(|_| {})); let result = std::panic::catch_unwind(|| { - deserialize_map(serialized_src); + deserialize_map(&serialized_src); }); assert!(result.is_err()); } @@ -1594,8 +1661,8 @@ mod utils { fn test_deserialize_map_all_chars_bytes() { // All 256 single-byte characters are allowed when emitting bytes. for i in 0..0xff { - let serialized_src: &[u8] = &[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; - let map = deserialize_map_bytes(serialized_src); + let serialized_src = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; + let map = deserialize_map_bytes(&serialized_src); // TODO(v0.3): fix arguments, so that maps can be reused without conversion. let map_refs: Vec<(&str, &[u8])> = map.iter().map(|x| (x.0.as_ref(), x.1.as_ref())).collect(); @@ -1622,17 +1689,28 @@ mod utils { }); } - #[cfg(feature = "strict-header-value")] #[cfg(nightly)] #[bench] - fn bench_deserialize_map(b: &mut Bencher) { + fn bench_serialize_map_typed(b: &mut Bencher) { + let map: Vec<(&str, HeaderValue)> = MAP + .iter() + .map(|x| (x.0, HeaderValue::from_static(x.1))) + .collect(); + let map_refs: Vec<(&str, &HeaderValue)> = map.iter().map(|x| (x.0, &x.1)).collect(); + b.iter(|| { + serialize_map_typed(test::black_box(&map_refs)); + }); + } + + #[cfg(nightly)] + #[bench] + fn bench_deserialize_map_typed(b: &mut Bencher) { let serialized_map: bytes::Bytes = SERIALIZED_MAP.into(); b.iter(|| { - deserialize_map(test::black_box(serialized_map.clone())); + deserialize_map_typed(test::black_box(serialized_map.clone())); }); } - #[cfg(not(feature = "strict-header-value"))] #[cfg(nightly)] #[bench] fn bench_deserialize_map(b: &mut Bencher) { diff --git a/src/traits.rs b/src/traits.rs index 21980da1..90c2084d 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -62,8 +62,7 @@ pub trait Context { hostcalls::enqueue_shared_queue(queue_id, value) } - #[cfg(feature = "strict-header-value")] - fn dispatch_http_call( + fn dispatch_http_call_typed( &self, upstream: &str, headers: Vec<(&str, &HeaderValue)>, @@ -74,7 +73,6 @@ pub trait Context { hostcalls::dispatch_http_call(upstream, headers, body, trailers, timeout) } - #[cfg(not(feature = "strict-header-value"))] fn dispatch_http_call( &self, upstream: &str, @@ -95,12 +93,10 @@ pub trait Context { ) { } - #[cfg(feature = "strict-header-value")] - fn get_http_call_response_headers(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map(MapType::HttpCallResponseHeaders).unwrap() + fn get_http_call_response_headers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpCallResponseHeaders).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_call_response_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpCallResponseHeaders).unwrap() } @@ -109,12 +105,10 @@ pub trait Context { hostcalls::get_map_bytes(MapType::HttpCallResponseHeaders).unwrap() } - #[cfg(feature = "strict-header-value")] - fn get_http_call_response_header(&self, name: &str) -> Option { - hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() + fn get_http_call_response_header_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpCallResponseTrailers, name).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_call_response_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseHeaders, name).unwrap() } @@ -127,12 +121,10 @@ pub trait Context { hostcalls::get_buffer(BufferType::HttpCallResponseBody, start, max_size).unwrap() } - #[cfg(feature = "strict-header-value")] - fn get_http_call_response_trailers(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map(MapType::HttpCallResponseTrailers).unwrap() + fn get_http_call_response_trailers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpCallResponseTrailers).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_call_response_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpCallResponseTrailers).unwrap() } @@ -141,12 +133,10 @@ pub trait Context { hostcalls::get_map_bytes(MapType::HttpCallResponseTrailers).unwrap() } - #[cfg(feature = "strict-header-value")] - fn get_http_call_response_trailer(&self, name: &str) -> Option { - hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() + fn get_http_call_response_trailer_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpCallResponseTrailers, name).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_call_response_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() } @@ -354,12 +344,10 @@ pub trait HttpContext: Context { Action::Continue } - #[cfg(feature = "strict-header-value")] - fn get_http_request_headers(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map(MapType::HttpRequestHeaders).unwrap() + fn get_http_request_headers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpRequestHeaders).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_request_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestHeaders).unwrap() } @@ -368,12 +356,10 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpRequestHeaders).unwrap() } - #[cfg(feature = "strict-header-value")] - fn set_http_request_headers(&self, headers: Vec<(&str, &HeaderValue)>) { - hostcalls::set_map(MapType::HttpRequestHeaders, headers).unwrap() + fn set_http_request_headers_typed(&self, headers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map_typed(MapType::HttpRequestHeaders, headers).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn set_http_request_headers(&self, headers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpRequestHeaders, headers).unwrap() } @@ -382,12 +368,10 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpRequestHeaders, headers).unwrap() } - #[cfg(feature = "strict-header-value")] - fn get_http_request_header(&self, name: &str) -> Option { - hostcalls::get_map_value(MapType::HttpRequestHeaders, name).unwrap() + fn get_http_request_header_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpRequestHeaders, name).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_request_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestHeaders, name).unwrap() } @@ -396,12 +380,10 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpRequestHeaders, name).unwrap() } - #[cfg(feature = "strict-header-value")] - fn set_http_request_header(&self, name: &str, value: Option<&HeaderValue>) { - hostcalls::set_map_value(MapType::HttpRequestHeaders, name, value).unwrap() + fn set_http_request_header_typed(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value_typed(MapType::HttpRequestHeaders, name, value).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn set_http_request_header(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } @@ -410,12 +392,10 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpRequestHeaders, name, value).unwrap() } - #[cfg(feature = "strict-header-value")] - fn add_http_request_header(&self, name: &str, value: &HeaderValue) { - hostcalls::add_map_value(MapType::HttpRequestHeaders, name, value).unwrap() + fn add_http_request_header_typed(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value_typed(MapType::HttpRequestHeaders, name, value).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn add_http_request_header(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } @@ -444,12 +424,10 @@ pub trait HttpContext: Context { Action::Continue } - #[cfg(feature = "strict-header-value")] - fn get_http_request_trailers(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map(MapType::HttpRequestTrailers).unwrap() + fn get_http_request_trailers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpRequestTrailers).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_request_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestTrailers).unwrap() } @@ -458,12 +436,10 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpRequestTrailers).unwrap() } - #[cfg(feature = "strict-header-value")] - fn set_http_request_trailers(&self, trailers: Vec<(&str, &HeaderValue)>) { - hostcalls::set_map(MapType::HttpRequestTrailers, trailers).unwrap() + fn set_http_request_trailers_typed(&self, trailers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map_typed(MapType::HttpRequestTrailers, trailers).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn set_http_request_trailers(&self, trailers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpRequestTrailers, trailers).unwrap() } @@ -472,12 +448,10 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpRequestTrailers, trailers).unwrap() } - #[cfg(feature = "strict-header-value")] - fn get_http_request_trailer(&self, name: &str) -> Option { - hostcalls::get_map_value(MapType::HttpRequestTrailers, name).unwrap() + fn get_http_request_trailer_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpRequestTrailers, name).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_request_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestTrailers, name).unwrap() } @@ -486,12 +460,10 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpRequestTrailers, name).unwrap() } - #[cfg(feature = "strict-header-value")] - fn set_http_request_trailer(&self, name: &str, value: Option<&HeaderValue>) { - hostcalls::set_map_value(MapType::HttpRequestTrailers, name, value).unwrap() + fn set_http_request_trailer_typed(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value_typed(MapType::HttpRequestTrailers, name, value).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn set_http_request_trailer(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } @@ -500,12 +472,10 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpRequestTrailers, name, value).unwrap() } - #[cfg(feature = "strict-header-value")] - fn add_http_request_trailer(&self, name: &str, value: &HeaderValue) { - hostcalls::add_map_value(MapType::HttpRequestTrailers, name, value).unwrap() + fn add_http_request_trailer_typed(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value_typed(MapType::HttpRequestTrailers, name, value).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn add_http_request_trailer(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } @@ -530,12 +500,10 @@ pub trait HttpContext: Context { Action::Continue } - #[cfg(feature = "strict-header-value")] - fn get_http_response_headers(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map(MapType::HttpResponseHeaders).unwrap() + fn get_http_response_headers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpResponseHeaders).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_response_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseHeaders).unwrap() } @@ -544,12 +512,10 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpResponseHeaders).unwrap() } - #[cfg(feature = "strict-header-value")] - fn set_http_response_headers(&self, headers: Vec<(&str, &HeaderValue)>) { - hostcalls::set_map(MapType::HttpResponseHeaders, headers).unwrap() + fn set_http_response_headers_typed(&self, headers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map_typed(MapType::HttpResponseHeaders, headers).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn set_http_response_headers(&self, headers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpResponseHeaders, headers).unwrap() } @@ -558,12 +524,10 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpResponseHeaders, headers).unwrap() } - #[cfg(feature = "strict-header-value")] - fn get_http_response_header(&self, name: &str) -> Option { - hostcalls::get_map_value(MapType::HttpResponseHeaders, name).unwrap() + fn get_http_response_header_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpResponseHeaders, name).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_response_header(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseHeaders, name).unwrap() } @@ -572,12 +536,10 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpResponseHeaders, name).unwrap() } - #[cfg(feature = "strict-header-value")] - fn set_http_response_header(&self, name: &str, value: Option<&HeaderValue>) { - hostcalls::set_map_value(MapType::HttpResponseHeaders, name, value).unwrap() + fn set_http_response_header_typed(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value_typed(MapType::HttpResponseHeaders, name, value).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn set_http_response_header(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } @@ -586,12 +548,10 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpResponseHeaders, name, value).unwrap() } - #[cfg(feature = "strict-header-value")] - fn add_http_response_header(&self, name: &str, value: &HeaderValue) { - hostcalls::add_map_value(MapType::HttpResponseHeaders, name, value).unwrap() + fn add_http_response_header_typed(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value_typed(MapType::HttpResponseHeaders, name, value).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn add_http_response_header(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } @@ -620,12 +580,10 @@ pub trait HttpContext: Context { Action::Continue } - #[cfg(feature = "strict-header-value")] - fn get_http_response_trailers(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map(MapType::HttpResponseTrailers).unwrap() + fn get_http_response_trailers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpResponseTrailers).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_response_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseTrailers).unwrap() } @@ -634,12 +592,10 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpResponseTrailers).unwrap() } - #[cfg(feature = "strict-header-value")] - fn set_http_response_trailers(&self, trailers: Vec<(&str, &HeaderValue)>) { - hostcalls::set_map(MapType::HttpResponseTrailers, trailers).unwrap() + fn set_http_response_trailers_typed(&self, trailers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map_typed(MapType::HttpResponseTrailers, trailers).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn set_http_response_trailers(&self, trailers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpResponseTrailers, trailers).unwrap() } @@ -648,12 +604,10 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpResponseTrailers, trailers).unwrap() } - #[cfg(feature = "strict-header-value")] - fn get_http_response_trailer(&self, name: &str) -> Option { - hostcalls::get_map_value(MapType::HttpResponseTrailers, name).unwrap() + fn get_http_response_trailer_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpResponseTrailers, name).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn get_http_response_trailer(&self, name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseTrailers, name).unwrap() } @@ -662,12 +616,10 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpResponseTrailers, name).unwrap() } - #[cfg(feature = "strict-header-value")] - fn set_http_response_trailer(&self, name: &str, value: Option<&HeaderValue>) { - hostcalls::set_map_value(MapType::HttpResponseTrailers, name, value).unwrap() + fn set_http_response_trailer_typed(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value_typed(MapType::HttpResponseTrailers, name, value).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn set_http_response_trailer(&self, name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } @@ -676,12 +628,10 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpResponseTrailers, name, value).unwrap() } - #[cfg(feature = "strict-header-value")] - fn add_http_response_trailer(&self, name: &str, value: &HeaderValue) { - hostcalls::add_map_value(MapType::HttpResponseTrailers, name, value).unwrap() + fn add_http_response_trailer_typed(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value_typed(MapType::HttpResponseTrailers, name, value).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn add_http_response_trailer(&self, name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } @@ -702,8 +652,7 @@ pub trait HttpContext: Context { hostcalls::reset_http_response().unwrap() } - #[cfg(feature = "strict-header-value")] - fn send_http_response( + fn send_http_response_typed( &self, status_code: u32, headers: Vec<(&str, &HeaderValue)>, @@ -712,7 +661,6 @@ pub trait HttpContext: Context { hostcalls::send_http_response(status_code, headers, body).unwrap() } - #[cfg(not(feature = "strict-header-value"))] fn send_http_response( &self, status_code: u32, diff --git a/src/types.rs b/src/types.rs index 16cb5621..91b160b5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -141,5 +141,4 @@ pub enum GrpcStatusCode { pub type Bytes = Vec; -#[cfg(feature = "strict-header-value")] pub use http::HeaderValue; From be9ea365df6a5fae8df0d9fcaf3737af0e98fbfd Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 24 Jan 2026 21:49:37 -0500 Subject: [PATCH 09/17] review: use _bytes() variant as the common implementation. Signed-off-by: Piotr Sikora --- src/hostcalls.rs | 105 +++++++++++++++++++++++++++++++---------------- src/traits.rs | 24 ++++++++++- 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/src/hostcalls.rs b/src/hostcalls.rs index 4f91d167..1e7d1e63 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -221,11 +221,15 @@ extern "C" { ) -> Status; } -pub fn set_map(map_type: MapType, map: Vec<(&str, V)>) -> Result<(), Status> +pub fn set_map(map_type: MapType, map: Vec<(&str, &str)>) -> Result<(), Status> { + set_map_bytes(map_type, map) +} + +pub fn set_map_bytes(map_type: MapType, map: Vec<(&str, V)>) -> Result<(), Status> where V: AsRef<[u8]>, { - let serialized_map = utils::serialize_map(&map); + let serialized_map = utils::serialize_map_bytes(&map); unsafe { match proxy_set_header_map_pairs(map_type, serialized_map.as_ptr(), serialized_map.len()) { Status::Ok => Ok(()), @@ -234,12 +238,8 @@ where } } -pub fn set_map_bytes(map_type: MapType, map: Vec<(&str, &[u8])>) -> Result<(), Status> { - set_map(map_type, map) -} - pub fn set_map_typed(map_type: MapType, map: Vec<(&str, &HeaderValue)>) -> Result<(), Status> { - set_map(map_type, map) + set_map_bytes(map_type, map) } #[cfg(not(test))] @@ -387,7 +387,11 @@ extern "C" { ) -> Status; } -pub fn set_map_value(map_type: MapType, key: &str, value: Option) -> Result<(), Status> +pub fn set_map_value(map_type: MapType, key: &str, value: Option<&str>) -> Result<(), Status> { + set_map_value_bytes(map_type, key, value) +} + +pub fn set_map_value_bytes(map_type: MapType, key: &str, value: Option) -> Result<(), Status> where V: AsRef<[u8]>, { @@ -412,20 +416,12 @@ where } } -pub fn set_map_value_bytes( - map_type: MapType, - key: &str, - value: Option<&[u8]>, -) -> Result<(), Status> { - set_map_value(map_type, key, value) -} - pub fn set_map_value_typed( map_type: MapType, key: &str, value: Option<&HeaderValue>, ) -> Result<(), Status> { - set_map_value(map_type, key, value) + set_map_value_bytes(map_type, key, value) } extern "C" { @@ -438,7 +434,11 @@ extern "C" { ) -> Status; } -pub fn add_map_value(map_type: MapType, key: &str, value: V) -> Result<(), Status> +pub fn add_map_value(map_type: MapType, key: &str, value: &str) -> Result<(), Status> { + add_map_value_bytes(map_type, key, value) +} + +pub fn add_map_value_bytes(map_type: MapType, key: &str, value: V) -> Result<(), Status> where V: AsRef<[u8]>, { @@ -456,16 +456,12 @@ where } } -pub fn add_map_value_bytes(map_type: MapType, key: &str, value: &[u8]) -> Result<(), Status> { - add_map_value(map_type, key, value) -} - pub fn add_map_value_typed( map_type: MapType, key: &str, value: &HeaderValue, ) -> Result<(), Status> { - add_map_value(map_type, key, value) + add_map_value_bytes(map_type, key, value) } extern "C" { @@ -789,7 +785,15 @@ extern "C" { ) -> Status; } -pub fn send_http_response( +pub fn send_http_response( + status_code: u32, + headers: Vec<(&str, &str)>, + body: Option<&[u8]>, +) -> Result<(), Status> { + send_http_response_bytes(status_code, headers, body) +} + +pub fn send_http_response_bytes( status_code: u32, headers: Vec<(&str, V)>, body: Option<&[u8]>, @@ -797,7 +801,7 @@ pub fn send_http_response( where V: AsRef<[u8]>, { - let serialized_headers = utils::serialize_map(&headers); + let serialized_headers = utils::serialize_map_bytes(&headers); unsafe { match proxy_send_local_response( status_code, @@ -815,6 +819,14 @@ where } } +pub fn send_http_response_typed( + status_code: u32, + headers: Vec<(&str, &HeaderValue)>, + body: Option<&[u8]>, +) -> Result<(), Status> { + send_http_response_bytes(status_code, headers, body) +} + pub fn send_grpc_response( grpc_status: GrpcStatusCode, grpc_status_message: Option<&str>, @@ -853,7 +865,17 @@ extern "C" { ) -> Status; } -pub fn dispatch_http_call( +pub fn dispatch_http_call( + upstream: &str, + headers: Vec<(&str, &str)>, + body: Option<&[u8]>, + trailers: Vec<(&str, &str)>, + timeout: Duration, +) -> Result { + dispatch_http_call_bytes(upstream, headers, body, trailers, timeout) +} + +pub fn dispatch_http_call_bytes( upstream: &str, headers: Vec<(&str, V)>, body: Option<&[u8]>, @@ -863,8 +885,8 @@ pub fn dispatch_http_call( where V: AsRef<[u8]>, { - let serialized_headers = utils::serialize_map(&headers); - let serialized_trailers = utils::serialize_map(&trailers); + let serialized_headers = utils::serialize_map_bytes(&headers); + let serialized_trailers = utils::serialize_map_bytes(&trailers); let mut return_token: u32 = 0; unsafe { match proxy_http_call( @@ -890,6 +912,16 @@ where } } +pub fn dispatch_http_call_typed( + upstream: &str, + headers: Vec<(&str, &HeaderValue)>, + body: Option<&[u8]>, + trailers: Vec<(&str, &HeaderValue)>, + timeout: Duration, +) -> Result { + dispatch_http_call_bytes(upstream, headers, body, trailers, timeout) +} + extern "C" { fn proxy_grpc_call( upstream_data: *const u8, @@ -1340,7 +1372,12 @@ mod utils { bytes } - pub(super) fn serialize_map(map: &[(&str, V)]) -> Bytes + #[cfg(test)] + pub(super) fn serialize_map(map: &[(&str, &str)]) -> Bytes { + serialize_map_bytes(map) + } + + pub(super) fn serialize_map_bytes(map: &[(&str, V)]) -> Bytes where V: AsRef<[u8]>, { @@ -1363,13 +1400,9 @@ mod utils { bytes } - pub(super) fn serialize_map_bytes(map: &[(&str, &[u8])]) -> Bytes { - serialize_map(map) - } - #[cfg(test)] pub(super) fn serialize_map_typed(map: &[(&str, &HeaderValue)]) -> Bytes { - serialize_map(map) + serialize_map_bytes(map) } pub(super) fn deserialize_map_typed(mut bytes: bytes::Bytes) -> Vec<(String, HeaderValue)> { @@ -1494,13 +1527,13 @@ mod utils { #[test] fn test_serialize_map_empty() { - let serialized_map = serialize_map::<&str>(&[]); + let serialized_map = serialize_map(&[]); assert_eq!(serialized_map, SERIALIZED_EMPTY_MAP); } #[test] fn test_serialize_map_empty_bytes() { - let serialized_map = serialize_map_bytes(&[]); + let serialized_map = serialize_map_bytes::<&[u8]>(&[]); assert_eq!(serialized_map, SERIALIZED_EMPTY_MAP); } diff --git a/src/traits.rs b/src/traits.rs index 90c2084d..04553829 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -70,7 +70,7 @@ pub trait Context { trailers: Vec<(&str, &HeaderValue)>, timeout: Duration, ) -> Result { - hostcalls::dispatch_http_call(upstream, headers, body, trailers, timeout) + hostcalls::dispatch_http_call_typed(upstream, headers, body, trailers, timeout) } fn dispatch_http_call( @@ -84,6 +84,17 @@ pub trait Context { hostcalls::dispatch_http_call(upstream, headers, body, trailers, timeout) } + fn dispatch_http_call_bytes( + &self, + upstream: &str, + headers: Vec<(&str, &[u8])>, + body: Option<&[u8]>, + trailers: Vec<(&str, &[u8])>, + timeout: Duration, + ) -> Result { + hostcalls::dispatch_http_call_bytes(upstream, headers, body, trailers, timeout) + } + fn on_http_call_response( &mut self, _token_id: u32, @@ -658,7 +669,7 @@ pub trait HttpContext: Context { headers: Vec<(&str, &HeaderValue)>, body: Option<&[u8]>, ) { - hostcalls::send_http_response(status_code, headers, body).unwrap() + hostcalls::send_http_response_typed(status_code, headers, body).unwrap() } fn send_http_response( @@ -670,6 +681,15 @@ pub trait HttpContext: Context { hostcalls::send_http_response(status_code, headers, body).unwrap() } + fn send_http_response_bytes( + &self, + status_code: u32, + headers: Vec<(&str, &[u8])>, + body: Option<&[u8]>, + ) { + hostcalls::send_http_response_bytes(status_code, headers, body).unwrap() + } + fn send_grpc_response( &self, grpc_status: GrpcStatusCode, From 7c38dafc6d911c65db34178c4275853f7c56a865 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 24 Jan 2026 21:53:56 -0500 Subject: [PATCH 10/17] review: reorder functions (original -> _bytes() -> _typed()). Signed-off-by: Piotr Sikora --- src/hostcalls.rs | 168 +++++++++++++++++++++++------------------------ src/traits.rs | 160 ++++++++++++++++++++++---------------------- 2 files changed, 164 insertions(+), 164 deletions(-) diff --git a/src/hostcalls.rs b/src/hostcalls.rs index 1e7d1e63..9fea765f 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -155,19 +155,15 @@ fn proxy_get_header_map_pairs( mocks::proxy_get_header_map_pairs(map_type, return_map_data, return_map_size) } -pub fn get_map_typed(map_type: MapType) -> Result, Status> { +pub fn get_map(map_type: MapType) -> Result, Status> { unsafe { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; match proxy_get_header_map_pairs(map_type, &mut return_data, &mut return_size) { Status::Ok => { if !return_data.is_null() { - let serialized_map = bytes::Bytes::from(Vec::from_raw_parts( - return_data, - return_size, - return_size, - )); - Ok(utils::deserialize_map_typed(serialized_map)) + let serialized_map = Vec::from_raw_parts(return_data, return_size, return_size); + Ok(utils::deserialize_map(&serialized_map)) } else { Ok(Vec::new()) } @@ -177,7 +173,7 @@ pub fn get_map_typed(map_type: MapType) -> Result, St } } -pub fn get_map(map_type: MapType) -> Result, Status> { +pub fn get_map_bytes(map_type: MapType) -> Result, Status> { unsafe { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; @@ -185,7 +181,7 @@ pub fn get_map(map_type: MapType) -> Result, Status> { Status::Ok => { if !return_data.is_null() { let serialized_map = Vec::from_raw_parts(return_data, return_size, return_size); - Ok(utils::deserialize_map(&serialized_map)) + Ok(utils::deserialize_map_bytes(&serialized_map)) } else { Ok(Vec::new()) } @@ -195,15 +191,19 @@ pub fn get_map(map_type: MapType) -> Result, Status> { } } -pub fn get_map_bytes(map_type: MapType) -> Result, Status> { +pub fn get_map_typed(map_type: MapType) -> Result, Status> { unsafe { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; match proxy_get_header_map_pairs(map_type, &mut return_data, &mut return_size) { Status::Ok => { if !return_data.is_null() { - let serialized_map = Vec::from_raw_parts(return_data, return_size, return_size); - Ok(utils::deserialize_map_bytes(&serialized_map)) + let serialized_map = bytes::Bytes::from(Vec::from_raw_parts( + return_data, + return_size, + return_size, + )); + Ok(utils::deserialize_map_typed(serialized_map)) } else { Ok(Vec::new()) } @@ -270,7 +270,7 @@ fn proxy_get_header_map_value( ) } -pub fn get_map_value_typed(map_type: MapType, key: &str) -> Result, Status> { +pub fn get_map_value(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; unsafe { @@ -283,16 +283,16 @@ pub fn get_map_value_typed(map_type: MapType, key: &str) -> Result { if !return_data.is_null() { - match HeaderValue::from_maybe_shared(Vec::from_raw_parts( - return_data, - return_size, - return_size, - )) { - Ok(value) => Ok(Some(value)), - Err(_) => panic!("invalid field value in: {}", key), - } + Ok(Some( + String::from_utf8(Vec::from_raw_parts( + return_data, + return_size, + return_size, + )) + .unwrap(), + )) } else { - Ok(Some(HeaderValue::from_static(""))) + Ok(Some(String::new())) } } Status::NotFound => Ok(None), @@ -301,7 +301,7 @@ pub fn get_map_value_typed(map_type: MapType, key: &str) -> Result Result, Status> { +pub fn get_map_value_bytes(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; unsafe { @@ -314,16 +314,13 @@ pub fn get_map_value(map_type: MapType, key: &str) -> Result, Sta ) { Status::Ok => { if !return_data.is_null() { - Ok(Some( - String::from_utf8(Vec::from_raw_parts( - return_data, - return_size, - return_size, - )) - .unwrap(), - )) + Ok(Some(Vec::from_raw_parts( + return_data, + return_size, + return_size, + ))) } else { - Ok(Some(String::new())) + Ok(Some(Vec::new())) } } Status::NotFound => Ok(None), @@ -332,7 +329,7 @@ pub fn get_map_value(map_type: MapType, key: &str) -> Result, Sta } } -pub fn get_map_value_bytes(map_type: MapType, key: &str) -> Result, Status> { +pub fn get_map_value_typed(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; unsafe { @@ -345,13 +342,16 @@ pub fn get_map_value_bytes(map_type: MapType, key: &str) -> Result ) { Status::Ok => { if !return_data.is_null() { - Ok(Some(Vec::from_raw_parts( + match HeaderValue::from_maybe_shared(Vec::from_raw_parts( return_data, return_size, return_size, - ))) + )) { + Ok(value) => Ok(Some(value)), + Err(_) => panic!("invalid field value in: {}", key), + } } else { - Ok(Some(Vec::new())) + Ok(Some(HeaderValue::from_static(""))) } } Status::NotFound => Ok(None), @@ -1405,31 +1405,6 @@ mod utils { serialize_map_bytes(map) } - pub(super) fn deserialize_map_typed(mut bytes: bytes::Bytes) -> Vec<(String, HeaderValue)> { - if bytes.is_empty() { - return Vec::new(); - } - let size = bytes.get_u32_le() as usize; - let mut sizes = bytes.split_to(size * 8); - let mut map = Vec::with_capacity(size); - for _ in 0..size { - let size = sizes.get_u32_le() as usize; - let key = bytes.split_to(size); - bytes.advance(1); - let size = sizes.get_u32_le() as usize; - let value = bytes.split_to(size); - bytes.advance(1); - map.push(( - String::from_utf8(key.to_vec()).unwrap(), - // We're intentionally using the unchecked variant in order to retain - // values accepted by the hosts and proxies that don't enforce strict - // RFC compliance on HTTP field values. - unsafe { HeaderValue::from_maybe_shared_unchecked(value) }, - )); - } - map - } - pub(super) fn deserialize_map(bytes: &[u8]) -> Vec<(String, String)> { if bytes.is_empty() { return Vec::new(); @@ -1475,6 +1450,31 @@ mod utils { map } + pub(super) fn deserialize_map_typed(mut bytes: bytes::Bytes) -> Vec<(String, HeaderValue)> { + if bytes.is_empty() { + return Vec::new(); + } + let size = bytes.get_u32_le() as usize; + let mut sizes = bytes.split_to(size * 8); + let mut map = Vec::with_capacity(size); + for _ in 0..size { + let size = sizes.get_u32_le() as usize; + let key = bytes.split_to(size); + bytes.advance(1); + let size = sizes.get_u32_le() as usize; + let value = bytes.split_to(size); + bytes.advance(1); + map.push(( + String::from_utf8(key.to_vec()).unwrap(), + // We're intentionally using the unchecked variant in order to retain + // values accepted by the hosts and proxies that don't enforce strict + // RFC compliance on HTTP field values. + unsafe { HeaderValue::from_maybe_shared_unchecked(value) }, + )); + } + map + } + #[cfg(test)] pub(super) mod tests { use super::*; @@ -1651,21 +1651,6 @@ mod utils { assert_eq!(serialized_map, SERIALIZED_MAP); } - #[test] - fn test_deserialize_map_all_chars_typed() { - // We're intentionally accepting all values to support hosts and proxies that - // don't enforce strict RFC compliance on HTTP field values. - for i in 0..0xff { - let serialized_src = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; - let map = deserialize_map_typed(serialized_src.to_vec().into()); - // TODO(v0.3): fix arguments, so that maps can be reused without conversion. - let map_refs: Vec<(&str, &HeaderValue)> = - map.iter().map(|x| (x.0.as_ref(), &x.1)).collect(); - let serialized_map = serialize_map_typed(&map_refs); - assert_eq!(serialized_map, serialized_src); - } - } - #[test] fn test_deserialize_map_all_chars() { // 0x00-0x7f are valid single-byte UTF-8 characters. @@ -1704,6 +1689,21 @@ mod utils { } } + #[test] + fn test_deserialize_map_all_chars_typed() { + // We're intentionally accepting all values to support hosts and proxies that + // don't enforce strict RFC compliance on HTTP field values. + for i in 0..0xff { + let serialized_src = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0]; + let map = deserialize_map_typed(serialized_src.to_vec().into()); + // TODO(v0.3): fix arguments, so that maps can be reused without conversion. + let map_refs: Vec<(&str, &HeaderValue)> = + map.iter().map(|x| (x.0.as_ref(), &x.1)).collect(); + let serialized_map = serialize_map_typed(&map_refs); + assert_eq!(serialized_map, serialized_src); + } + } + #[cfg(nightly)] #[bench] fn bench_serialize_map(b: &mut Bencher) { @@ -1737,28 +1737,28 @@ mod utils { #[cfg(nightly)] #[bench] - fn bench_deserialize_map_typed(b: &mut Bencher) { - let serialized_map: bytes::Bytes = SERIALIZED_MAP.into(); + fn bench_deserialize_map(b: &mut Bencher) { + let serialized_map = SERIALIZED_MAP.to_vec(); b.iter(|| { - deserialize_map_typed(test::black_box(serialized_map.clone())); + deserialize_map(test::black_box(&serialized_map)); }); } #[cfg(nightly)] #[bench] - fn bench_deserialize_map(b: &mut Bencher) { + fn bench_deserialize_map_bytes(b: &mut Bencher) { let serialized_map = SERIALIZED_MAP.to_vec(); b.iter(|| { - deserialize_map(test::black_box(&serialized_map)); + deserialize_map_bytes(test::black_box(&serialized_map)); }); } #[cfg(nightly)] #[bench] - fn bench_deserialize_map_bytes(b: &mut Bencher) { - let serialized_map = SERIALIZED_MAP.to_vec(); + fn bench_deserialize_map_typed(b: &mut Bencher) { + let serialized_map: bytes::Bytes = SERIALIZED_MAP.into(); b.iter(|| { - deserialize_map_bytes(test::black_box(&serialized_map)); + deserialize_map_typed(test::black_box(serialized_map.clone())); }); } } diff --git a/src/traits.rs b/src/traits.rs index 04553829..16cd6b5f 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -62,17 +62,6 @@ pub trait Context { hostcalls::enqueue_shared_queue(queue_id, value) } - fn dispatch_http_call_typed( - &self, - upstream: &str, - headers: Vec<(&str, &HeaderValue)>, - body: Option<&[u8]>, - trailers: Vec<(&str, &HeaderValue)>, - timeout: Duration, - ) -> Result { - hostcalls::dispatch_http_call_typed(upstream, headers, body, trailers, timeout) - } - fn dispatch_http_call( &self, upstream: &str, @@ -95,6 +84,17 @@ pub trait Context { hostcalls::dispatch_http_call_bytes(upstream, headers, body, trailers, timeout) } + fn dispatch_http_call_typed( + &self, + upstream: &str, + headers: Vec<(&str, &HeaderValue)>, + body: Option<&[u8]>, + trailers: Vec<(&str, &HeaderValue)>, + timeout: Duration, + ) -> Result { + hostcalls::dispatch_http_call_typed(upstream, headers, body, trailers, timeout) + } + fn on_http_call_response( &mut self, _token_id: u32, @@ -104,10 +104,6 @@ pub trait Context { ) { } - fn get_http_call_response_headers_typed(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map_typed(MapType::HttpCallResponseHeaders).unwrap() - } - fn get_http_call_response_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpCallResponseHeaders).unwrap() } @@ -116,8 +112,8 @@ pub trait Context { hostcalls::get_map_bytes(MapType::HttpCallResponseHeaders).unwrap() } - fn get_http_call_response_header_typed(&self, name: &str) -> Option { - hostcalls::get_map_value_typed(MapType::HttpCallResponseTrailers, name).unwrap() + fn get_http_call_response_headers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpCallResponseHeaders).unwrap() } fn get_http_call_response_header(&self, name: &str) -> Option { @@ -128,12 +124,12 @@ pub trait Context { hostcalls::get_map_value_bytes(MapType::HttpCallResponseHeaders, name).unwrap() } - fn get_http_call_response_body(&self, start: usize, max_size: usize) -> Option { - hostcalls::get_buffer(BufferType::HttpCallResponseBody, start, max_size).unwrap() + fn get_http_call_response_header_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpCallResponseTrailers, name).unwrap() } - fn get_http_call_response_trailers_typed(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map_typed(MapType::HttpCallResponseTrailers).unwrap() + fn get_http_call_response_body(&self, start: usize, max_size: usize) -> Option { + hostcalls::get_buffer(BufferType::HttpCallResponseBody, start, max_size).unwrap() } fn get_http_call_response_trailers(&self) -> Vec<(String, String)> { @@ -144,8 +140,8 @@ pub trait Context { hostcalls::get_map_bytes(MapType::HttpCallResponseTrailers).unwrap() } - fn get_http_call_response_trailer_typed(&self, name: &str) -> Option { - hostcalls::get_map_value_typed(MapType::HttpCallResponseTrailers, name).unwrap() + fn get_http_call_response_trailers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpCallResponseTrailers).unwrap() } fn get_http_call_response_trailer(&self, name: &str) -> Option { @@ -156,6 +152,10 @@ pub trait Context { hostcalls::get_map_value_bytes(MapType::HttpCallResponseTrailers, name).unwrap() } + fn get_http_call_response_trailer_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpCallResponseTrailers, name).unwrap() + } + fn dispatch_grpc_call( &self, upstream_name: &str, @@ -355,10 +355,6 @@ pub trait HttpContext: Context { Action::Continue } - fn get_http_request_headers_typed(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map_typed(MapType::HttpRequestHeaders).unwrap() - } - fn get_http_request_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestHeaders).unwrap() } @@ -367,8 +363,8 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpRequestHeaders).unwrap() } - fn set_http_request_headers_typed(&self, headers: Vec<(&str, &HeaderValue)>) { - hostcalls::set_map_typed(MapType::HttpRequestHeaders, headers).unwrap() + fn get_http_request_headers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpRequestHeaders).unwrap() } fn set_http_request_headers(&self, headers: Vec<(&str, &str)>) { @@ -379,8 +375,8 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpRequestHeaders, headers).unwrap() } - fn get_http_request_header_typed(&self, name: &str) -> Option { - hostcalls::get_map_value_typed(MapType::HttpRequestHeaders, name).unwrap() + fn set_http_request_headers_typed(&self, headers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map_typed(MapType::HttpRequestHeaders, headers).unwrap() } fn get_http_request_header(&self, name: &str) -> Option { @@ -391,8 +387,8 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpRequestHeaders, name).unwrap() } - fn set_http_request_header_typed(&self, name: &str, value: Option<&HeaderValue>) { - hostcalls::set_map_value_typed(MapType::HttpRequestHeaders, name, value).unwrap() + fn get_http_request_header_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpRequestHeaders, name).unwrap() } fn set_http_request_header(&self, name: &str, value: Option<&str>) { @@ -403,8 +399,8 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpRequestHeaders, name, value).unwrap() } - fn add_http_request_header_typed(&self, name: &str, value: &HeaderValue) { - hostcalls::add_map_value_typed(MapType::HttpRequestHeaders, name, value).unwrap() + fn set_http_request_header_typed(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value_typed(MapType::HttpRequestHeaders, name, value).unwrap() } fn add_http_request_header(&self, name: &str, value: &str) { @@ -415,6 +411,10 @@ pub trait HttpContext: Context { hostcalls::add_map_value_bytes(MapType::HttpRequestHeaders, name, value).unwrap() } + fn add_http_request_header_typed(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value_typed(MapType::HttpRequestHeaders, name, value).unwrap() + } + fn remove_http_request_header(&self, name: &str) { hostcalls::remove_map_value(MapType::HttpRequestHeaders, name).unwrap() } @@ -435,10 +435,6 @@ pub trait HttpContext: Context { Action::Continue } - fn get_http_request_trailers_typed(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map_typed(MapType::HttpRequestTrailers).unwrap() - } - fn get_http_request_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestTrailers).unwrap() } @@ -447,8 +443,8 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpRequestTrailers).unwrap() } - fn set_http_request_trailers_typed(&self, trailers: Vec<(&str, &HeaderValue)>) { - hostcalls::set_map_typed(MapType::HttpRequestTrailers, trailers).unwrap() + fn get_http_request_trailers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpRequestTrailers).unwrap() } fn set_http_request_trailers(&self, trailers: Vec<(&str, &str)>) { @@ -459,8 +455,8 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpRequestTrailers, trailers).unwrap() } - fn get_http_request_trailer_typed(&self, name: &str) -> Option { - hostcalls::get_map_value_typed(MapType::HttpRequestTrailers, name).unwrap() + fn set_http_request_trailers_typed(&self, trailers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map_typed(MapType::HttpRequestTrailers, trailers).unwrap() } fn get_http_request_trailer(&self, name: &str) -> Option { @@ -471,8 +467,8 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpRequestTrailers, name).unwrap() } - fn set_http_request_trailer_typed(&self, name: &str, value: Option<&HeaderValue>) { - hostcalls::set_map_value_typed(MapType::HttpRequestTrailers, name, value).unwrap() + fn get_http_request_trailer_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpRequestTrailers, name).unwrap() } fn set_http_request_trailer(&self, name: &str, value: Option<&str>) { @@ -483,8 +479,8 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpRequestTrailers, name, value).unwrap() } - fn add_http_request_trailer_typed(&self, name: &str, value: &HeaderValue) { - hostcalls::add_map_value_typed(MapType::HttpRequestTrailers, name, value).unwrap() + fn set_http_request_trailer_typed(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value_typed(MapType::HttpRequestTrailers, name, value).unwrap() } fn add_http_request_trailer(&self, name: &str, value: &str) { @@ -495,6 +491,10 @@ pub trait HttpContext: Context { hostcalls::add_map_value_bytes(MapType::HttpRequestTrailers, name, value).unwrap() } + fn add_http_request_trailer_typed(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value_typed(MapType::HttpRequestTrailers, name, value).unwrap() + } + fn remove_http_request_trailer(&self, name: &str) { hostcalls::remove_map_value(MapType::HttpRequestTrailers, name).unwrap() } @@ -511,10 +511,6 @@ pub trait HttpContext: Context { Action::Continue } - fn get_http_response_headers_typed(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map_typed(MapType::HttpResponseHeaders).unwrap() - } - fn get_http_response_headers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseHeaders).unwrap() } @@ -523,8 +519,8 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpResponseHeaders).unwrap() } - fn set_http_response_headers_typed(&self, headers: Vec<(&str, &HeaderValue)>) { - hostcalls::set_map_typed(MapType::HttpResponseHeaders, headers).unwrap() + fn get_http_response_headers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpResponseHeaders).unwrap() } fn set_http_response_headers(&self, headers: Vec<(&str, &str)>) { @@ -535,8 +531,8 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpResponseHeaders, headers).unwrap() } - fn get_http_response_header_typed(&self, name: &str) -> Option { - hostcalls::get_map_value_typed(MapType::HttpResponseHeaders, name).unwrap() + fn set_http_response_headers_typed(&self, headers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map_typed(MapType::HttpResponseHeaders, headers).unwrap() } fn get_http_response_header(&self, name: &str) -> Option { @@ -547,8 +543,8 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpResponseHeaders, name).unwrap() } - fn set_http_response_header_typed(&self, name: &str, value: Option<&HeaderValue>) { - hostcalls::set_map_value_typed(MapType::HttpResponseHeaders, name, value).unwrap() + fn get_http_response_header_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpResponseHeaders, name).unwrap() } fn set_http_response_header(&self, name: &str, value: Option<&str>) { @@ -559,8 +555,8 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpResponseHeaders, name, value).unwrap() } - fn add_http_response_header_typed(&self, name: &str, value: &HeaderValue) { - hostcalls::add_map_value_typed(MapType::HttpResponseHeaders, name, value).unwrap() + fn set_http_response_header_typed(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value_typed(MapType::HttpResponseHeaders, name, value).unwrap() } fn add_http_response_header(&self, name: &str, value: &str) { @@ -571,6 +567,10 @@ pub trait HttpContext: Context { hostcalls::add_map_value_bytes(MapType::HttpResponseHeaders, name, value).unwrap() } + fn add_http_response_header_typed(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value_typed(MapType::HttpResponseHeaders, name, value).unwrap() + } + fn remove_http_response_header(&self, name: &str) { hostcalls::remove_map_value(MapType::HttpResponseHeaders, name).unwrap() } @@ -591,10 +591,6 @@ pub trait HttpContext: Context { Action::Continue } - fn get_http_response_trailers_typed(&self) -> Vec<(String, HeaderValue)> { - hostcalls::get_map_typed(MapType::HttpResponseTrailers).unwrap() - } - fn get_http_response_trailers(&self) -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseTrailers).unwrap() } @@ -603,8 +599,8 @@ pub trait HttpContext: Context { hostcalls::get_map_bytes(MapType::HttpResponseTrailers).unwrap() } - fn set_http_response_trailers_typed(&self, trailers: Vec<(&str, &HeaderValue)>) { - hostcalls::set_map_typed(MapType::HttpResponseTrailers, trailers).unwrap() + fn get_http_response_trailers_typed(&self) -> Vec<(String, HeaderValue)> { + hostcalls::get_map_typed(MapType::HttpResponseTrailers).unwrap() } fn set_http_response_trailers(&self, trailers: Vec<(&str, &str)>) { @@ -615,8 +611,8 @@ pub trait HttpContext: Context { hostcalls::set_map_bytes(MapType::HttpResponseTrailers, trailers).unwrap() } - fn get_http_response_trailer_typed(&self, name: &str) -> Option { - hostcalls::get_map_value_typed(MapType::HttpResponseTrailers, name).unwrap() + fn set_http_response_trailers_typed(&self, trailers: Vec<(&str, &HeaderValue)>) { + hostcalls::set_map_typed(MapType::HttpResponseTrailers, trailers).unwrap() } fn get_http_response_trailer(&self, name: &str) -> Option { @@ -627,8 +623,8 @@ pub trait HttpContext: Context { hostcalls::get_map_value_bytes(MapType::HttpResponseTrailers, name).unwrap() } - fn set_http_response_trailer_typed(&self, name: &str, value: Option<&HeaderValue>) { - hostcalls::set_map_value_typed(MapType::HttpResponseTrailers, name, value).unwrap() + fn get_http_response_trailer_typed(&self, name: &str) -> Option { + hostcalls::get_map_value_typed(MapType::HttpResponseTrailers, name).unwrap() } fn set_http_response_trailer(&self, name: &str, value: Option<&str>) { @@ -639,8 +635,8 @@ pub trait HttpContext: Context { hostcalls::set_map_value_bytes(MapType::HttpResponseTrailers, name, value).unwrap() } - fn add_http_response_trailer_typed(&self, name: &str, value: &HeaderValue) { - hostcalls::add_map_value_typed(MapType::HttpResponseTrailers, name, value).unwrap() + fn set_http_response_trailer_typed(&self, name: &str, value: Option<&HeaderValue>) { + hostcalls::set_map_value_typed(MapType::HttpResponseTrailers, name, value).unwrap() } fn add_http_response_trailer(&self, name: &str, value: &str) { @@ -651,6 +647,10 @@ pub trait HttpContext: Context { hostcalls::add_map_value_bytes(MapType::HttpResponseTrailers, name, value).unwrap() } + fn add_http_response_trailer_typed(&self, name: &str, value: &HeaderValue) { + hostcalls::add_map_value_typed(MapType::HttpResponseTrailers, name, value).unwrap() + } + fn remove_http_response_trailer(&self, name: &str) { hostcalls::remove_map_value(MapType::HttpResponseTrailers, name).unwrap() } @@ -663,15 +663,6 @@ pub trait HttpContext: Context { hostcalls::reset_http_response().unwrap() } - fn send_http_response_typed( - &self, - status_code: u32, - headers: Vec<(&str, &HeaderValue)>, - body: Option<&[u8]>, - ) { - hostcalls::send_http_response_typed(status_code, headers, body).unwrap() - } - fn send_http_response( &self, status_code: u32, @@ -690,6 +681,15 @@ pub trait HttpContext: Context { hostcalls::send_http_response_bytes(status_code, headers, body).unwrap() } + fn send_http_response_typed( + &self, + status_code: u32, + headers: Vec<(&str, &HeaderValue)>, + body: Option<&[u8]>, + ) { + hostcalls::send_http_response_typed(status_code, headers, body).unwrap() + } + fn send_grpc_response( &self, grpc_status: GrpcStatusCode, From b1104645f8d32c9f35c4678e4ee9a3c9340260a2 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 24 Jan 2026 22:03:26 -0500 Subject: [PATCH 11/17] review: style. Signed-off-by: Piotr Sikora --- src/hostcalls.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hostcalls.rs b/src/hostcalls.rs index 9fea765f..64f36aec 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -1520,7 +1520,7 @@ mod utils { ]; #[rustfmt::skip] - static SERIALIZED_EMPTY_MAP: &[u8] = &[ + static SERIALIZED_MAP_EMPTY: &[u8] = &[ // num entries 0, 0, 0, 0, ]; @@ -1528,26 +1528,26 @@ mod utils { #[test] fn test_serialize_map_empty() { let serialized_map = serialize_map(&[]); - assert_eq!(serialized_map, SERIALIZED_EMPTY_MAP); + assert_eq!(serialized_map, SERIALIZED_MAP_EMPTY); } #[test] fn test_serialize_map_empty_bytes() { let serialized_map = serialize_map_bytes::<&[u8]>(&[]); - assert_eq!(serialized_map, SERIALIZED_EMPTY_MAP); + assert_eq!(serialized_map, SERIALIZED_MAP_EMPTY); } #[test] fn test_serialize_map_empty_typed() { let serialized_map = serialize_map_typed(&[]); - assert_eq!(serialized_map, SERIALIZED_EMPTY_MAP); + assert_eq!(serialized_map, SERIALIZED_MAP_EMPTY); } #[test] fn test_deserialize_map_empty() { let map = deserialize_map(&[]); assert_eq!(map, []); - let map = deserialize_map(SERIALIZED_EMPTY_MAP); + let map = deserialize_map(SERIALIZED_MAP_EMPTY); assert_eq!(map, []); } @@ -1555,7 +1555,7 @@ mod utils { fn test_deserialize_map_empty_bytes() { let map = deserialize_map_bytes(&[]); assert_eq!(map, []); - let map = deserialize_map_bytes(SERIALIZED_EMPTY_MAP); + let map = deserialize_map_bytes(SERIALIZED_MAP_EMPTY); assert_eq!(map, []); } @@ -1563,7 +1563,7 @@ mod utils { fn test_deserialize_map_empty_typed() { let map = deserialize_map_typed(bytes::Bytes::new()); assert_eq!(map, []); - let map = deserialize_map_typed(SERIALIZED_EMPTY_MAP.into()); + let map = deserialize_map_typed(SERIALIZED_MAP_EMPTY.into()); assert_eq!(map, []); } From a847b32445bc4b3d8d9050cfc5d25de22a44be58 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 24 Jan 2026 22:15:23 -0500 Subject: [PATCH 12/17] review: fix format in examples. Signed-off-by: Piotr Sikora --- examples/grpc_auth_random/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/grpc_auth_random/src/lib.rs b/examples/grpc_auth_random/src/lib.rs index cc7c79b0..aa5f5f04 100644 --- a/examples/grpc_auth_random/src/lib.rs +++ b/examples/grpc_auth_random/src/lib.rs @@ -61,7 +61,10 @@ impl HttpContext for GrpcAuthRandom { } fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action { - self.set_http_response_header_typed("Powered-By", Some(&HeaderValue::from_static("proxy-wasm"))); + self.set_http_response_header_typed( + "Powered-By", + Some(&HeaderValue::from_static("proxy-wasm")), + ); Action::Continue } } From b0e5d9bed89cedf1894d6ff79e7787722092c983 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 24 Jan 2026 23:19:33 -0500 Subject: [PATCH 13/17] review: convert remaining examples. Signed-off-by: Piotr Sikora --- examples/envoy_filter_metadata/src/lib.rs | 15 ++++++++++----- examples/http_auth_random/src/lib.rs | 17 ++++++++++------- examples/http_body/src/lib.rs | 2 +- examples/http_config/src/lib.rs | 10 +++++----- examples/http_headers/src/lib.rs | 4 ++-- 5 files changed, 28 insertions(+), 20 deletions(-) diff --git a/examples/envoy_filter_metadata/src/lib.rs b/examples/envoy_filter_metadata/src/lib.rs index 2a2356df..fd8c5d42 100644 --- a/examples/envoy_filter_metadata/src/lib.rs +++ b/examples/envoy_filter_metadata/src/lib.rs @@ -33,12 +33,17 @@ impl HttpContext for MetadataHttp { "envoy.filters.http.lua", "uppercased-custom-metadata", ]) { - Some(metadata) => match String::from_utf8(metadata) { - Ok(data) => { - self.send_http_response( + Some(metadata) => match HeaderValue::from_maybe_shared(metadata) { + Ok(value) => { + self.send_http_response_typed( 200, - vec![("Powered-By", "proxy-wasm"), ("uppercased-metadata", &data)], - Some(format!("Custom response with Envoy metadata: {data:?}\n").as_bytes()), + vec![ + ("Powered-By", &HeaderValue::from_static("proxy-wasm")), + ("uppercased-metadata", &value), + ], + Some( + format!("Custom response with Envoy metadata: {value:?}\n").as_bytes(), + ), ); Action::Pause } diff --git a/examples/http_auth_random/src/lib.rs b/examples/http_auth_random/src/lib.rs index 4e539713..dd0ee8fe 100644 --- a/examples/http_auth_random/src/lib.rs +++ b/examples/http_auth_random/src/lib.rs @@ -26,12 +26,12 @@ struct HttpAuthRandom; impl HttpContext for HttpAuthRandom { fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action { - self.dispatch_http_call( + self.dispatch_http_call_typed( "httpbin", vec![ - (":method", "GET"), - (":path", "/bytes/1"), - (":authority", "httpbin.org"), + (":method", &HeaderValue::from_static("GET")), + (":path", &HeaderValue::from_static("/bytes/1")), + (":authority", &HeaderValue::from_static("httpbin.org")), ], None, vec![], @@ -42,7 +42,10 @@ impl HttpContext for HttpAuthRandom { } fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action { - self.set_http_response_header("Powered-By", Some("proxy-wasm")); + self.set_http_response_header_typed( + "Powered-By", + Some(&HeaderValue::from_static("proxy-wasm")), + ); Action::Continue } } @@ -58,9 +61,9 @@ impl Context for HttpAuthRandom { } } info!("Access forbidden."); - self.send_http_response( + self.send_http_response_typed( 403, - vec![("Powered-By", "proxy-wasm")], + vec![("Powered-By", &HeaderValue::from_static("proxy-wasm"))], Some(b"Access forbidden.\n"), ); } diff --git a/examples/http_body/src/lib.rs b/examples/http_body/src/lib.rs index 397886a8..1d37d445 100644 --- a/examples/http_body/src/lib.rs +++ b/examples/http_body/src/lib.rs @@ -44,7 +44,7 @@ impl HttpContext for HttpBody { // the body later, then clients will break. So remove it. // We must do this here, because once we exit this function we // can no longer modify the response headers. - self.set_http_response_header("content-length", None); + self.set_http_response_header_typed("content-length", None); Action::Continue } diff --git a/examples/http_config/src/lib.rs b/examples/http_config/src/lib.rs index 7493bf5f..0328aaf8 100644 --- a/examples/http_config/src/lib.rs +++ b/examples/http_config/src/lib.rs @@ -19,26 +19,26 @@ proxy_wasm::main! {{ proxy_wasm::set_log_level(LogLevel::Trace); proxy_wasm::set_root_context(|_| -> Box { Box::new(HttpConfigHeaderRoot { - header_content: String::new(), + header_content: HeaderValue::from_static(""), }) }); }} struct HttpConfigHeader { - header_content: String, + header_content: HeaderValue, } impl Context for HttpConfigHeader {} impl HttpContext for HttpConfigHeader { fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action { - self.add_http_response_header("custom-header", self.header_content.as_str()); + self.add_http_response_header_typed("custom-header", &self.header_content); Action::Continue } } struct HttpConfigHeaderRoot { - header_content: String, + header_content: HeaderValue, } impl Context for HttpConfigHeaderRoot {} @@ -46,7 +46,7 @@ impl Context for HttpConfigHeaderRoot {} impl RootContext for HttpConfigHeaderRoot { fn on_configure(&mut self, _: usize) -> bool { if let Some(config_bytes) = self.get_plugin_configuration() { - self.header_content = String::from_utf8(config_bytes).unwrap() + self.header_content = HeaderValue::from_maybe_shared(config_bytes).unwrap() } true } diff --git a/examples/http_headers/src/lib.rs b/examples/http_headers/src/lib.rs index 76cacff5..e7aca745 100644 --- a/examples/http_headers/src/lib.rs +++ b/examples/http_headers/src/lib.rs @@ -52,8 +52,8 @@ impl HttpContext for HttpHeaders { ); } - match self.get_http_request_header(":path") { - Some(path) if path == "/hello" => { + match self.get_http_request_header_typed(":path") { + Some(path) if path.as_bytes() == b"/hello" => { self.send_http_response_typed( 200, vec![ From 25bcdf1475f559bf1f13b50ad413ca72996084c9 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 24 Jan 2026 23:14:40 -0500 Subject: [PATCH 14/17] review: mark UTF-8 variants as deprecated. Signed-off-by: Piotr Sikora --- src/hostcalls.rs | 9 +++++ src/traits.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/src/hostcalls.rs b/src/hostcalls.rs index 64f36aec..1c95ceb0 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -155,6 +155,7 @@ fn proxy_get_header_map_pairs( mocks::proxy_get_header_map_pairs(map_type, return_map_data, return_map_size) } +#[deprecated(since = "0.2.5", note = "use `get_map_typed` instead")] pub fn get_map(map_type: MapType) -> Result, Status> { unsafe { let mut return_data: *mut u8 = null_mut(); @@ -221,6 +222,7 @@ extern "C" { ) -> Status; } +#[deprecated(since = "0.2.5", note = "use `set_map_typed` instead")] pub fn set_map(map_type: MapType, map: Vec<(&str, &str)>) -> Result<(), Status> { set_map_bytes(map_type, map) } @@ -270,6 +272,7 @@ fn proxy_get_header_map_value( ) } +#[deprecated(since = "0.2.5", note = "use `get_map_value_typed` instead")] pub fn get_map_value(map_type: MapType, key: &str) -> Result, Status> { let mut return_data: *mut u8 = null_mut(); let mut return_size: usize = 0; @@ -387,6 +390,7 @@ extern "C" { ) -> Status; } +#[deprecated(since = "0.2.5", note = "use `set_map_value_typed` instead")] pub fn set_map_value(map_type: MapType, key: &str, value: Option<&str>) -> Result<(), Status> { set_map_value_bytes(map_type, key, value) } @@ -434,6 +438,7 @@ extern "C" { ) -> Status; } +#[deprecated(since = "0.2.5", note = "use `add_map_value_typed` instead")] pub fn add_map_value(map_type: MapType, key: &str, value: &str) -> Result<(), Status> { add_map_value_bytes(map_type, key, value) } @@ -785,6 +790,7 @@ extern "C" { ) -> Status; } +#[deprecated(since = "0.2.5", note = "use `send_http_response_typed` instead")] pub fn send_http_response( status_code: u32, headers: Vec<(&str, &str)>, @@ -865,6 +871,7 @@ extern "C" { ) -> Status; } +#[deprecated(since = "0.2.5", note = "use `dispatch_http_call_typed` instead")] pub fn dispatch_http_call( upstream: &str, headers: Vec<(&str, &str)>, @@ -1314,6 +1321,7 @@ mod tests { #[mockalloc::test] fn test_get_map_no_leaks() { + #[allow(deprecated)] let result = super::get_map(MapType::HttpRequestHeaders); assert!(result.is_ok()); } @@ -1332,6 +1340,7 @@ mod tests { #[mockalloc::test] fn test_get_map_value_no_leaks() { + #[allow(deprecated)] let result = super::get_map_value(MapType::HttpRequestHeaders, "foo"); assert!(result.is_ok()); } diff --git a/src/traits.rs b/src/traits.rs index 16cd6b5f..ff0a70ed 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -62,6 +62,7 @@ pub trait Context { hostcalls::enqueue_shared_queue(queue_id, value) } + #[deprecated(since = "0.2.5", note = "use `dispatch_http_call_typed` instead")] fn dispatch_http_call( &self, upstream: &str, @@ -70,6 +71,7 @@ pub trait Context { trailers: Vec<(&str, &str)>, timeout: Duration, ) -> Result { + #[allow(deprecated)] hostcalls::dispatch_http_call(upstream, headers, body, trailers, timeout) } @@ -104,7 +106,12 @@ pub trait Context { ) { } + #[deprecated( + since = "0.2.5", + note = "use `get_http_call_response_headers_typed` instead" + )] fn get_http_call_response_headers(&self) -> Vec<(String, String)> { + #[allow(deprecated)] hostcalls::get_map(MapType::HttpCallResponseHeaders).unwrap() } @@ -116,7 +123,12 @@ pub trait Context { hostcalls::get_map_typed(MapType::HttpCallResponseHeaders).unwrap() } + #[deprecated( + since = "0.2.5", + note = "use `get_http_call_response_header_typed` instead" + )] fn get_http_call_response_header(&self, name: &str) -> Option { + #[allow(deprecated)] hostcalls::get_map_value(MapType::HttpCallResponseHeaders, name).unwrap() } @@ -132,7 +144,12 @@ pub trait Context { hostcalls::get_buffer(BufferType::HttpCallResponseBody, start, max_size).unwrap() } + #[deprecated( + since = "0.2.5", + note = "use `get_http_call_response_trailers_typed` instead" + )] fn get_http_call_response_trailers(&self) -> Vec<(String, String)> { + #[allow(deprecated)] hostcalls::get_map(MapType::HttpCallResponseTrailers).unwrap() } @@ -144,7 +161,12 @@ pub trait Context { hostcalls::get_map_typed(MapType::HttpCallResponseTrailers).unwrap() } + #[deprecated( + since = "0.2.5", + note = "use `get_http_call_response_trailer_typed` instead" + )] fn get_http_call_response_trailer(&self, name: &str) -> Option { + #[allow(deprecated)] hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() } @@ -355,7 +377,9 @@ pub trait HttpContext: Context { Action::Continue } + #[deprecated(since = "0.2.5", note = "use `get_http_request_headers_typed` instead")] fn get_http_request_headers(&self) -> Vec<(String, String)> { + #[allow(deprecated)] hostcalls::get_map(MapType::HttpRequestHeaders).unwrap() } @@ -367,7 +391,9 @@ pub trait HttpContext: Context { hostcalls::get_map_typed(MapType::HttpRequestHeaders).unwrap() } + #[deprecated(since = "0.2.5", note = "use `set_http_request_headers_typed` instead")] fn set_http_request_headers(&self, headers: Vec<(&str, &str)>) { + #[allow(deprecated)] hostcalls::set_map(MapType::HttpRequestHeaders, headers).unwrap() } @@ -379,7 +405,9 @@ pub trait HttpContext: Context { hostcalls::set_map_typed(MapType::HttpRequestHeaders, headers).unwrap() } + #[deprecated(since = "0.2.5", note = "use `get_http_request_header_typed` instead")] fn get_http_request_header(&self, name: &str) -> Option { + #[allow(deprecated)] hostcalls::get_map_value(MapType::HttpRequestHeaders, name).unwrap() } @@ -391,7 +419,9 @@ pub trait HttpContext: Context { hostcalls::get_map_value_typed(MapType::HttpRequestHeaders, name).unwrap() } + #[deprecated(since = "0.2.5", note = "use `set_http_request_header_typed` instead")] fn set_http_request_header(&self, name: &str, value: Option<&str>) { + #[allow(deprecated)] hostcalls::set_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } @@ -403,7 +433,9 @@ pub trait HttpContext: Context { hostcalls::set_map_value_typed(MapType::HttpRequestHeaders, name, value).unwrap() } + #[deprecated(since = "0.2.5", note = "use `add_http_request_header_typed` instead")] fn add_http_request_header(&self, name: &str, value: &str) { + #[allow(deprecated)] hostcalls::add_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } @@ -435,7 +467,12 @@ pub trait HttpContext: Context { Action::Continue } + #[deprecated( + since = "0.2.5", + note = "use `get_http_request_trailers_typed` instead" + )] fn get_http_request_trailers(&self) -> Vec<(String, String)> { + #[allow(deprecated)] hostcalls::get_map(MapType::HttpRequestTrailers).unwrap() } @@ -447,7 +484,12 @@ pub trait HttpContext: Context { hostcalls::get_map_typed(MapType::HttpRequestTrailers).unwrap() } + #[deprecated( + since = "0.2.5", + note = "use `set_http_request_trailers_typed` instead" + )] fn set_http_request_trailers(&self, trailers: Vec<(&str, &str)>) { + #[allow(deprecated)] hostcalls::set_map(MapType::HttpRequestTrailers, trailers).unwrap() } @@ -459,7 +501,9 @@ pub trait HttpContext: Context { hostcalls::set_map_typed(MapType::HttpRequestTrailers, trailers).unwrap() } + #[deprecated(since = "0.2.5", note = "use `get_http_request_trailer_typed` instead")] fn get_http_request_trailer(&self, name: &str) -> Option { + #[allow(deprecated)] hostcalls::get_map_value(MapType::HttpRequestTrailers, name).unwrap() } @@ -471,7 +515,9 @@ pub trait HttpContext: Context { hostcalls::get_map_value_typed(MapType::HttpRequestTrailers, name).unwrap() } + #[deprecated(since = "0.2.5", note = "use `set_http_request_trailer_typed` instead")] fn set_http_request_trailer(&self, name: &str, value: Option<&str>) { + #[allow(deprecated)] hostcalls::set_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } @@ -483,7 +529,9 @@ pub trait HttpContext: Context { hostcalls::set_map_value_typed(MapType::HttpRequestTrailers, name, value).unwrap() } + #[deprecated(since = "0.2.5", note = "use `add_http_request_trailer_typed` instead")] fn add_http_request_trailer(&self, name: &str, value: &str) { + #[allow(deprecated)] hostcalls::add_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } @@ -511,7 +559,12 @@ pub trait HttpContext: Context { Action::Continue } + #[deprecated( + since = "0.2.5", + note = "use `get_http_response_headers_typed` instead" + )] fn get_http_response_headers(&self) -> Vec<(String, String)> { + #[allow(deprecated)] hostcalls::get_map(MapType::HttpResponseHeaders).unwrap() } @@ -523,7 +576,12 @@ pub trait HttpContext: Context { hostcalls::get_map_typed(MapType::HttpResponseHeaders).unwrap() } + #[deprecated( + since = "0.2.5", + note = "use `set_http_response_headers_typed` instead" + )] fn set_http_response_headers(&self, headers: Vec<(&str, &str)>) { + #[allow(deprecated)] hostcalls::set_map(MapType::HttpResponseHeaders, headers).unwrap() } @@ -535,7 +593,9 @@ pub trait HttpContext: Context { hostcalls::set_map_typed(MapType::HttpResponseHeaders, headers).unwrap() } + #[deprecated(since = "0.2.5", note = "use `get_http_response_header_typed` instead")] fn get_http_response_header(&self, name: &str) -> Option { + #[allow(deprecated)] hostcalls::get_map_value(MapType::HttpResponseHeaders, name).unwrap() } @@ -547,7 +607,9 @@ pub trait HttpContext: Context { hostcalls::get_map_value_typed(MapType::HttpResponseHeaders, name).unwrap() } + #[deprecated(since = "0.2.5", note = "use `set_http_response_header_typed` instead")] fn set_http_response_header(&self, name: &str, value: Option<&str>) { + #[allow(deprecated)] hostcalls::set_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } @@ -559,7 +621,9 @@ pub trait HttpContext: Context { hostcalls::set_map_value_typed(MapType::HttpResponseHeaders, name, value).unwrap() } + #[deprecated(since = "0.2.5", note = "use `add_http_response_header_typed` instead")] fn add_http_response_header(&self, name: &str, value: &str) { + #[allow(deprecated)] hostcalls::add_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } @@ -591,7 +655,12 @@ pub trait HttpContext: Context { Action::Continue } + #[deprecated( + since = "0.2.5", + note = "use `get_http_response_trailers_typed` instead" + )] fn get_http_response_trailers(&self) -> Vec<(String, String)> { + #[allow(deprecated)] hostcalls::get_map(MapType::HttpResponseTrailers).unwrap() } @@ -603,7 +672,12 @@ pub trait HttpContext: Context { hostcalls::get_map_typed(MapType::HttpResponseTrailers).unwrap() } + #[deprecated( + since = "0.2.5", + note = "use `set_http_response_trailers_typed` instead" + )] fn set_http_response_trailers(&self, trailers: Vec<(&str, &str)>) { + #[allow(deprecated)] hostcalls::set_map(MapType::HttpResponseTrailers, trailers).unwrap() } @@ -615,7 +689,12 @@ pub trait HttpContext: Context { hostcalls::set_map_typed(MapType::HttpResponseTrailers, trailers).unwrap() } + #[deprecated( + since = "0.2.5", + note = "use `get_http_response_trailer_typed` instead" + )] fn get_http_response_trailer(&self, name: &str) -> Option { + #[allow(deprecated)] hostcalls::get_map_value(MapType::HttpResponseTrailers, name).unwrap() } @@ -627,7 +706,12 @@ pub trait HttpContext: Context { hostcalls::get_map_value_typed(MapType::HttpResponseTrailers, name).unwrap() } + #[deprecated( + since = "0.2.5", + note = "use `set_http_response_trailer_typed` instead" + )] fn set_http_response_trailer(&self, name: &str, value: Option<&str>) { + #[allow(deprecated)] hostcalls::set_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } @@ -639,7 +723,12 @@ pub trait HttpContext: Context { hostcalls::set_map_value_typed(MapType::HttpResponseTrailers, name, value).unwrap() } + #[deprecated( + since = "0.2.5", + note = "use `add_http_response_trailer_typed` instead" + )] fn add_http_response_trailer(&self, name: &str, value: &str) { + #[allow(deprecated)] hostcalls::add_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } @@ -663,12 +752,14 @@ pub trait HttpContext: Context { hostcalls::reset_http_response().unwrap() } + #[deprecated(since = "0.2.5", note = "use `send_http_response_typed` instead")] fn send_http_response( &self, status_code: u32, headers: Vec<(&str, &str)>, body: Option<&[u8]>, ) { + #[allow(deprecated)] hostcalls::send_http_response(status_code, headers, body).unwrap() } From 3384e48de30c1c00a86abbd90c5498bbda14bbe8 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Wed, 11 Feb 2026 15:53:11 -0500 Subject: [PATCH 15/17] review: gate mocks on "mockalloc" feature. Signed-off-by: Piotr Sikora --- src/hostcalls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hostcalls.rs b/src/hostcalls.rs index f2b5c4d3..a3fac873 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -244,7 +244,7 @@ pub fn set_map_typed(map_type: MapType, map: Vec<(&str, &HeaderValue)>) -> Resul set_map_bytes(map_type, map) } -#[cfg(not(test))] +#[cfg(not(all(test, feature = "mockalloc")))] extern "C" { fn proxy_get_header_map_value( map_type: MapType, @@ -255,7 +255,7 @@ extern "C" { ) -> Status; } -#[cfg(test)] +#[cfg(all(test, feature = "mockalloc"))] fn proxy_get_header_map_value( map_type: MapType, key_data: *const u8, From 204ebd30f48ac82a87825bab378ac6d982b85128 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Wed, 11 Feb 2026 15:59:19 -0500 Subject: [PATCH 16/17] review: update bytes to v1.11.1. Signed-off-by: Piotr Sikora --- MODULE.bazel | 2 +- bazel/cargo/Cargo.Bazel.lock | 4 ++-- bazel/cargo/remote/BUILD.bazel | 6 +++--- ...bytes-1.11.0.bazel => BUILD.bytes-1.11.1.bazel} | 2 +- bazel/cargo/remote/BUILD.http-1.4.0.bazel | 2 +- bazel/cargo/remote/defs.bzl | 14 +++++++------- 6 files changed, 15 insertions(+), 15 deletions(-) rename bazel/cargo/remote/{BUILD.bytes-1.11.0.bazel => BUILD.bytes-1.11.1.bazel} (99%) diff --git a/MODULE.bazel b/MODULE.bazel index b00c10c0..d907b0a6 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -52,7 +52,7 @@ crates_deps = use_extension("//bazel:extensions.bzl", "crates_deps") use_repo( crates_deps, "crates_vendor", - "crates_vendor__bytes-1.11.0", + "crates_vendor__bytes-1.11.1", "crates_vendor__hashbrown-0.16.0", "crates_vendor__http-1.4.0", "crates_vendor__log-0.4.27", diff --git a/bazel/cargo/Cargo.Bazel.lock b/bazel/cargo/Cargo.Bazel.lock index de93b60e..2498d622 100644 --- a/bazel/cargo/Cargo.Bazel.lock +++ b/bazel/cargo/Cargo.Bazel.lock @@ -10,9 +10,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "equivalent" diff --git a/bazel/cargo/remote/BUILD.bazel b/bazel/cargo/remote/BUILD.bazel index 9aaf33f9..f1d1e02f 100644 --- a/bazel/cargo/remote/BUILD.bazel +++ b/bazel/cargo/remote/BUILD.bazel @@ -32,14 +32,14 @@ filegroup( # Workspace Member Dependencies alias( - name = "bytes-1.11.0", - actual = "@crates_vendor__bytes-1.11.0//:bytes", + name = "bytes-1.11.1", + actual = "@crates_vendor__bytes-1.11.1//:bytes", tags = ["manual"], ) alias( name = "bytes", - actual = "@crates_vendor__bytes-1.11.0//:bytes", + actual = "@crates_vendor__bytes-1.11.1//:bytes", tags = ["manual"], ) diff --git a/bazel/cargo/remote/BUILD.bytes-1.11.0.bazel b/bazel/cargo/remote/BUILD.bytes-1.11.1.bazel similarity index 99% rename from bazel/cargo/remote/BUILD.bytes-1.11.0.bazel rename to bazel/cargo/remote/BUILD.bytes-1.11.1.bazel index 016a6df8..05c72588 100644 --- a/bazel/cargo/remote/BUILD.bytes-1.11.0.bazel +++ b/bazel/cargo/remote/BUILD.bytes-1.11.1.bazel @@ -96,5 +96,5 @@ rust_library( "@rules_rust//rust/platform:x86_64-unknown-uefi": [], "//conditions:default": ["@platforms//:incompatible"], }), - version = "1.11.0", + version = "1.11.1", ) diff --git a/bazel/cargo/remote/BUILD.http-1.4.0.bazel b/bazel/cargo/remote/BUILD.http-1.4.0.bazel index 52375ecd..4e880f0b 100644 --- a/bazel/cargo/remote/BUILD.http-1.4.0.bazel +++ b/bazel/cargo/remote/BUILD.http-1.4.0.bazel @@ -98,7 +98,7 @@ rust_library( }), version = "1.4.0", deps = [ - "@crates_vendor__bytes-1.11.0//:bytes", + "@crates_vendor__bytes-1.11.1//:bytes", "@crates_vendor__itoa-1.0.17//:itoa", ], ) diff --git a/bazel/cargo/remote/defs.bzl b/bazel/cargo/remote/defs.bzl index d7272a48..199ebfe7 100644 --- a/bazel/cargo/remote/defs.bzl +++ b/bazel/cargo/remote/defs.bzl @@ -295,7 +295,7 @@ def aliases( _NORMAL_DEPENDENCIES = { "": { _COMMON_CONDITION: { - "bytes": Label("@crates_vendor//:bytes-1.11.0"), + "bytes": Label("@crates_vendor//:bytes-1.11.1"), "hashbrown": Label("@crates_vendor//:hashbrown-0.16.0"), "http": Label("@crates_vendor//:http-1.4.0"), "log": Label("@crates_vendor//:log-0.4.27"), @@ -423,12 +423,12 @@ def crate_repositories(): maybe( http_archive, - name = "crates_vendor__bytes-1.11.0", - sha256 = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3", + name = "crates_vendor__bytes-1.11.1", + sha256 = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33", type = "tar.gz", - urls = ["https://static.crates.io/crates/bytes/1.11.0/download"], - strip_prefix = "bytes-1.11.0", - build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.bytes-1.11.0.bazel"), + urls = ["https://static.crates.io/crates/bytes/1.11.1/download"], + strip_prefix = "bytes-1.11.1", + build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.bytes-1.11.1.bazel"), ) maybe( @@ -492,7 +492,7 @@ def crate_repositories(): ) return [ - struct(repo = "crates_vendor__bytes-1.11.0", is_dev_dep = False), + struct(repo = "crates_vendor__bytes-1.11.1", is_dev_dep = False), struct(repo = "crates_vendor__hashbrown-0.16.0", is_dev_dep = False), struct(repo = "crates_vendor__http-1.4.0", is_dev_dep = False), struct(repo = "crates_vendor__log-0.4.27", is_dev_dep = False), From a4d1e4acd74ea0ac164252fa40df9ee110870dec Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Thu, 12 Feb 2026 00:42:06 -0500 Subject: [PATCH 17/17] review: use _unchecked variant also for individual values. Signed-off-by: Piotr Sikora --- src/hostcalls.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/hostcalls.rs b/src/hostcalls.rs index a3fac873..d1371f77 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -345,14 +345,12 @@ pub fn get_map_value_typed(map_type: MapType, key: &str) -> Result { if !return_data.is_null() { - match HeaderValue::from_maybe_shared(Vec::from_raw_parts( - return_data, - return_size, - return_size, - )) { - Ok(value) => Ok(Some(value)), - Err(_) => panic!("invalid field value in: {}", key), - } + // We're intentionally using the unchecked variant in order to retain + // values accepted by the hosts and proxies that don't enforce strict + // RFC compliance on HTTP field values. + Ok(Some(HeaderValue::from_maybe_shared_unchecked( + Vec::from_raw_parts(return_data, return_size, return_size), + ))) } else { Ok(Some(HeaderValue::from_static(""))) }