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..eb96231e 100644 --- a/BUILD +++ b/BUILD @@ -39,6 +39,22 @@ 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:bytes", + "//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 +68,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..fd322592 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,15 @@ 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:bytes", "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..3a373e6d 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" @@ -41,6 +70,8 @@ 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 f62c1da8..46e22fdb 100644 --- a/bazel/cargo/remote/BUILD.bazel +++ b/bazel/cargo/remote/BUILD.bazel @@ -31,12 +31,24 @@ 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", 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..97ddadb4 100644 --- a/bazel/cargo/remote/defs.bzl +++ b/bazel/cargo/remote/defs.bzl @@ -295,7 +295,9 @@ 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"), }, }, @@ -413,6 +415,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 +435,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 +465,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", @@ -454,6 +496,8 @@ 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/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..630bc3e4 100644 --- a/src/hostcalls.rs +++ b/src/hostcalls.rs @@ -145,6 +145,27 @@ 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 = + bytes::Bytes::from(std::slice::from_raw_parts(return_data, 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 +210,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 +224,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 +237,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 +346,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 +376,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 +389,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 +408,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 +732,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 +796,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 +1173,10 @@ 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; + #[cfg(feature = "header-value")] + use bytes::Buf; use std::convert::TryFrom; pub(super) fn serialize_property_path(path: Vec<&str>) -> Bytes { @@ -1159,46 +1196,60 @@ 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(mut bytes: bytes::Bytes) -> Vec<(String, HeaderValue)> { + if bytes.is_empty() { + return Vec::new(); } - 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 = 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) }, + )); } - 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;