This plugin demonstrates conditional header replacement with different behaviors for request and response headers. For request headers, it only replaces existing headers (conditional overwrite). For response headers, it always sets the header value, creating it if it doesn't exist (unconditional upsert). Use this plugin when you need to standardize header values, enforce header policies, or learn the differences between header manipulation APIs. It operates during the request headers and response headers processing phases.
-
The proxy receives an HTTP request and invokes
on_http_request_headers. -
The plugin checks if the
RequestHeaderheader exists by reading its value. -
If the header exists: The plugin replaces its value with
"changed". -
If the header doesn't exist: The plugin does nothing (header is not added).
This pattern is useful when you want to normalize existing headers without adding new ones.
-
The proxy receives an HTTP response from the upstream server and invokes
on_http_response_headers. -
The plugin unconditionally calls
replaceResponseHeader()/ReplaceHttpResponseHeader()/set_http_response_header()withResponseHeader: changed. -
If the header exists: Its value is replaced with
"changed". -
If the header doesn't exist: The header is created with value
"changed".
This pattern is useful when you want to ensure a header is always present with a specific value.
- Conditional logic: Demonstrates checking for header existence before mutation using
getRequestHeader()->size()(C++) or equivalent patterns in other languages. - API distinction: Contrasts the difference between appending values (
addHeader) versus upserting values (replaceHeader). - Phase-specific behavior: Runs in both request and response phases, doing a conditional overwrite for requests and an unconditional upsert for responses.
No configuration required. Header names (RequestHeader, ResponseHeader) and values ("changed") are hardcoded in the plugin source.
Customization:
// C++
const auto header_key = "X-Custom-Header";
replaceRequestHeader(header_key, "new-value");// Rust
const REQUEST_HEADER_KEY: &str = "X-Custom-Header";
const REQUEST_HEADER_VALUE: &str = "new-value";Build the plugin for any supported language from the plugins/ directory:
# Rust
bazelisk build //samples/overwrite_header:plugin_rust.wasm
# C++
bazelisk build //samples/overwrite_header:plugin_cpp.wasm
# Go
bazelisk build //samples/overwrite_header:plugin_go.wasmRun the unit tests defined in tests.textpb:
# Using Docker (recommended)
docker run -it -v $(pwd):/mnt \
us-docker.pkg.dev/service-extensions-samples/plugins/wasm-tester:main \
--proto /mnt/samples/overwrite_header/tests.textpb \
--plugin /mnt/bazel-bin/samples/overwrite_header/plugin_rust.wasm
# Using Bazel (all languages)
bazelisk test --test_output=all //samples/overwrite_header:testsDerived from tests.textpb:
| Scenario | Description |
|---|---|
| DoNotAddRequestHeader | Skips modifying the request header since the target header is completely missing. |
| DoAddResponseHeader | Unconditionally adds the response header even though it was originally absent. |
| OverwriteRequestHeader | Conditionally overwrites the value of the existing request header. |
| OverwriteResponseHeader | Unconditionally overwrites the value of the existing response header. |
Request headers (conditional):
- Normalize authentication tokens only if present
- Sanitize user-provided headers without adding defaults
- Enforce format requirements on existing headers
Response headers (unconditional):
- Ensure security headers are always present (e.g.,
X-Frame-Options,X-Content-Type-Options) - Override upstream header values with policy-enforced values
- Add or update cache-control headers
Example: Security headers:
FilterHeadersStatus onResponseHeaders(...) override {
// Always enforce security headers
replaceResponseHeader("X-Frame-Options", "DENY");
replaceResponseHeader("X-Content-Type-Options", "nosniff");
replaceResponseHeader("Strict-Transport-Security", "max-age=31536000");
return FilterHeadersStatus::Continue;
}