Wasm C++ filter

Requirements

Sandbox environment

Setup your sandbox environment with Docker and Docker Compose, and clone the Envoy repository with Git.

curl

Used to make HTTP requests.

Compatibility

The provided Wasm binary was compiled for the x86_64 architecture. If you would like to use this sandbox with the arm64 architecture, change directory to examples/wasm-cc and skip to Step 3.

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.

Change to the examples/wasm-cc folder in the Envoy repo, and start the composition:

  1. $ pwd
  2. envoy/examples/wasm-cc
  3. $ docker-compose build --pull
  4. $ docker-compose up -d
  5. $ docker-compose ps
  6. Name Command State Ports
  7. -----------------------------------------------------------------------------------------------
  8. wasm_proxy_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp
  9. 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.

  1. $ curl -s http://localhost:8000 | grep "Hello, world"
  2. }Hello, world

The filter also sets the content-type header to text/plain, and adds a custom x-wasm-custom header.

  1. $ curl -v http://localhost:8000 | grep "content-type: "
  2. content-type: text/plain; charset=utf-8
  3. $ curl -v http://localhost:8000 | grep "x-wasm-custom: "
  4. 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:

  1. --- /tmp/tmppez1lu4l/generated/rst/start/sandboxes/_include/wasm-cc/envoy_filter_http_wasm_example.cc
  2. +++ /tmp/tmppez1lu4l/generated/rst/start/sandboxes/_include/wasm-cc/envoy_filter_http_wasm_updated_example.cc
  3. @@ -65,8 +65,8 @@
  4. for (auto& p : pairs) {
  5. LOG_INFO(std::string(p.first) + std::string(" -> ") + std::string(p.second));
  6. }
  7. - addResponseHeader("X-Wasm-custom", "FOO");
  8. - replaceResponseHeader("content-type", "text/plain; charset=utf-8");
  9. + addResponseHeader("X-Wasm-custom", "BAR");
  10. + replaceResponseHeader("content-type", "text/html; charset=utf-8");
  11. removeResponseHeader("content-length");
  12. return FilterHeadersStatus::Continue;
  13. }
  14. @@ -78,9 +78,9 @@
  15. return FilterDataStatus::Continue;
  16. }
  17. -FilterDataStatus ExampleContext::onResponseBody(size_t body_buffer_length,
  18. +FilterDataStatus ExampleContext::onResponseBody(size_t /* body_buffer_length */,
  19. bool /* end_of_stream */) {
  20. - setBuffer(WasmBufferType::HttpResponseBody, 0, body_buffer_length, "Hello, world\n");
  21. + setBuffer(WasmBufferType::HttpResponseBody, 0, 17, "Hello, Wasm world");
  22. return FilterDataStatus::Continue;
  23. }

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.

Stop the proxy server and compile the Wasm binary with the updated code:

  1. $ docker-compose stop proxy
  2. $ docker-compose -f docker-compose-wasm.yaml up --remove-orphans wasm_compile_update

The compiled binary should now be in the lib folder.

  1. $ ls -l lib
  2. total 120
  3. -r-xr-xr-x 1 root root 59641 Oct 20 00:00 envoy_filter_http_wasm_example.wasm
  4. -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:

  1. 1FROM envoyproxy/envoy-dev:latest
  2. 2COPY ./envoy.yaml /etc/envoy.yaml
  3. 3COPY ./lib/envoy_filter_http_wasm_example.wasm /lib/envoy_filter_http_wasm_example.wasm
  4. 4RUN chmod go+r /etc/envoy.yaml /lib/envoy_filter_http_wasm_example.wasm
  5. 5CMD ["/usr/local/bin/envoy", "-c", "/etc/envoy.yaml", "--service-cluster", "proxy"]

Replace this line with the following:

  1. COPY ./lib/envoy_filter_http_wasm_updated_example.wasm /lib/envoy_filter_http_wasm_example.wasm

Now, rebuild and start the proxy container.

  1. $ 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.

  1. $ curl -s http://localhost:8000 | grep "Hello, Wasm world"
  2. }Hello, Wasm world

The content-type and x-wasm-custom headers should also have changed

  1. $ curl -v http://localhost:8000 | grep "content-type: "
  2. content-type: text/html; charset=utf-8
  3. $ curl -v http://localhost:8000 | grep "x-wasm-custom: "
  4. 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)