Wasm C++ filter
This sandbox demonstrates a basic Envoy Wasm filter written in C++ which injects
content into the body of an HTTP
response, and adds and updates some headers.
It also takes you through the steps required to build your own C++ Wasm filter, and run it with Envoy.
Step 1: Start all of our containers
First lets start the containers - an Envoy proxy which uses a Wasm Filter, and a backend which echos back our request. The Envoy configuration exposes two listeners, the first one listens in port 8000 which contains the wasm filter in the listener filter chain. The second one listens in port 8001 routing to a cluster containing the wasm filter in the cluster filter chain.
Change to the examples/wasm-cc
folder in the Envoy repo, and start the composition:
$ pwd
envoy/examples/wasm-cc
$ docker compose pull
$ docker compose up --build -d
$ docker compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------
wasm_proxy_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8001->8001/tcp
wasm_web_service_1 node ./index.js Up
Step 2: Check web response
The Wasm filter should inject “Hello, world” at the end of the response body when you make a request to the proxy.
$ curl -s http://localhost:8000 | grep "Hello, world"
}Hello, world
The filter also sets the content-type
header to text/plain
, and adds a custom x-wasm-custom
header.
$ curl -v http://localhost:8000 | grep "content-type: "
content-type: text/plain; charset=utf-8
$ curl -v http://localhost:8000 | grep "x-wasm-custom: "
x-wasm-custom: FOO
Similar outputs could be obtained in the second listener routing to the cluster with upstream wasm filter.
$ curl -s http://localhost:8001 | grep "Hello, world"
}Hello, world
$ curl -v http://localhost:8001 | grep "content-type: "
content-type: text/plain; charset=utf-8
$ curl -v http://localhost:8001 | grep "x-wasm-custom: "
x-wasm-custom: FOO
Step 3: Compile the updated filter
There are two source code files provided for the Wasm filter.
envoy_filter_http_wasm_example.cc
provides the source code for
the included prebuilt binary.
envoy_filter_http_wasm_updated_example.cc
makes a few
changes to the original.
The following diff shows the changes that have been made:
--- /tmp/tmpn6c6h0xn/generated/rst/start/sandboxes/_include/wasm-cc/envoy_filter_http_wasm_example.cc
+++ /tmp/tmpn6c6h0xn/generated/rst/start/sandboxes/_include/wasm-cc/envoy_filter_http_wasm_updated_example.cc
@@ -65,8 +65,8 @@
for (auto& p : pairs) {
LOG_INFO(std::string(p.first) + std::string(" -> ") + std::string(p.second));
}
- addResponseHeader("X-Wasm-custom", "FOO");
- replaceResponseHeader("content-type", "text/plain; charset=utf-8");
+ addResponseHeader("X-Wasm-custom", "BAR");
+ replaceResponseHeader("content-type", "text/html; charset=utf-8");
removeResponseHeader("content-length");
return FilterHeadersStatus::Continue;
}
@@ -78,9 +78,9 @@
return FilterDataStatus::Continue;
}
-FilterDataStatus ExampleContext::onResponseBody(size_t body_buffer_length,
+FilterDataStatus ExampleContext::onResponseBody(size_t /* body_buffer_length */,
bool /* end_of_stream */) {
- setBuffer(WasmBufferType::HttpResponseBody, 0, body_buffer_length, "Hello, world\n");
+ setBuffer(WasmBufferType::HttpResponseBody, 0, 17, "Hello, Wasm world");
return FilterDataStatus::Continue;
}
Warning
These instructions for compiling an updated Wasm binary use the envoyproxy/envoy-build-ubuntu image. You will need 4-5GB of disk space to accommodate this image.
Export UID
from your host system. This will ensure that the binary created inside the build container has the same permissions
as your host user:
$ export UID
Note
The build composition is designed to work in a similar way to the ./ci/run_envoy_docker.sh
command in the Envoy repo.
Bazel temporary artefacts are created in /tmp/envoy-docker-build
with the uid taken from the UID
env var.
Stop the proxy server and compile the Wasm binary with the updated code:
$ docker compose stop proxy
$ docker compose -f docker-compose-wasm.yaml up --remove-orphans wasm_compile_update
The compiled binary should now be in the lib
folder.
$ ls -l lib
total 120
-r-xr-xr-x 1 root root 59641 Oct 20 00:00 envoy_filter_http_wasm_example.wasm
-r-xr-xr-x 1 root root 59653 Oct 20 10:16 envoy_filter_http_wasm_updated_example.wasm
Step 4: Edit the Dockerfile and restart the proxy
Edit the Dockerfile-proxy
recipe provided in the example to use the updated binary you created in step 3.
Find the COPY
line that adds the Wasm binary to the image:
1FROM envoyproxy/envoy:dev
2COPY ./envoy.yaml /etc/envoy.yaml
3COPY ./lib/envoy_filter_http_wasm_example.wasm /lib/envoy_filter_http_wasm_example.wasm
4RUN chmod go+r /etc/envoy.yaml /lib/envoy_filter_http_wasm_example.wasm
5CMD ["/usr/local/bin/envoy", "-c", "/etc/envoy.yaml", "--service-cluster", "proxy"]
Replace this line with the following:
COPY ./lib/envoy_filter_http_wasm_updated_example.wasm /lib/envoy_filter_http_wasm_example.wasm
Now, rebuild and start the proxy container.
$ docker compose up --build -d proxy
Step 5: Check the proxy has been updated
The Wasm filter should instead inject “Hello, Wasm world” at the end of the response body.
$ curl -s http://localhost:8000 | grep "Hello, Wasm world"
}Hello, Wasm world
The content-type
and x-wasm-custom
headers should also have changed
$ curl -v http://localhost:8000 | grep "content-type: "
content-type: text/html; charset=utf-8
$ curl -v http://localhost:8000 | grep "x-wasm-custom: "
x-wasm-custom: BAR
See also
- Envoy Wasm filter
Further information about the Envoy Wasm filter.
- Envoy Wasm API(V3)
The Envoy Wasm API - version 3.
- Proxy Wasm C++ SDK
WebAssembly for proxies (C++ SDK)