Setting the HttpRequestBody buffer from inside an httpCall callback in a WASM filter
- Dominant language
- C++
- Stars
- 28.9k
- Forks
- 5.6k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 428
Description
I am writing a custom Envoy filter using the [WASM C++ SDK](https://github.com/proxy-wasm/proxy-wasm-cpp-sdk) and I am trying to make an `httpCall` that is able to `setBuffer` the `WasmBufferType::HttpRequestBody` from inside its callback. The `httpCall` is invoked inside the overriden `onRequestBody` method of the filter's `Context` for the reason I explain below.
So the use case is that the filter intercepts certain incoming HTTP POST requests and passes their body as payload to a sidecar server using `httpCall`, which then does some manipulation on the body. The callback will then update the body of the request and invoke `continueRequest()` so that the POST request continues to its destination.
I am able to successfully update the body of a request as follows (simplified code snippet):
```cpp
// Works fine.
FilterDataStatus FilterContext::onRequestBody(size_t body_buffer_length, bool end_of_stream) {
if (!end_of_stream) {
auto body = getBufferBytes(WasmBufferType::HttpRequestBody, 0, body_buffer_length);
auto updated_body = ...; // some logic that edits the JSON body.
WasmResult result = setBuffer(WasmBufferType::HttpRequestBody, 0, body_buffer_length, updated_body); // This succeeds.
}
return FilterDataStatus::Continue;
}
```
However, if I try to do this via an `httpCall` callback, like this (simplified some custom logic that does not matter to focus on the issue):
```cpp
FilterDataStatus FilterContext::onRequestBody(size_t body_buffer_length, bool end_of_stream) {
if (!end_of_stream) {
auto body = getBufferBytes(WasmBufferType::HttpRequestBody, 0, body_buffer_length);
rootContext()->remoteCall(id(), body->toString()); // This call happens in the root context below.
return FilterDataStatus::StopIterationAndBuffer;
}
return FilterDataStatus::Continue;
}
// Function in the root context.
void FilterRootContext::remoteCall(uint32_t stream_context_id, std::string request_body) {
// some custom logic
...
// Calls the sidecar server, which manipulates the body of the HTTP POST request.
WasmResult http_call_result = httpCall(cluster_name_, headers, request_body, HeaderStringPairs(), 5000,
[stream_context_id, request_body](uint32_t header_count, size_t body_size, uint32_t trailer_count) {
// Callback is triggered inside root context so we need to switch the
// background context from root context to the current stream context.
getContext(stream_context_id)->setEffectiveContext();
auto status = getHeaderMapValue(WasmHeaderMapType::HttpCallResponseHeaders, ":status")->toString(); // 200
if (status != "200") {
// error handling with local response
sendLocalResponse(...);
return;
}
// The sidecar server gives an updated body in its response.
auto response_body = getBufferBytes(WasmBufferType::HttpCallResponseBody, 0, body_size)->toString();
// Returns an empty string! But this shouldn't match the request_body that was bind to this callback?
auto test = getBufferBytes(WasmBufferType::HttpRequestBody, 0, request_body.size())->toString();
// This fails with BadRequest!
WasmResult result = setBuffer(WasmBufferType::HttpRequestBody, 0, request_body.size(), response_body);
// Continue request with the updated body.
continueRequest();
});
// Error handling if httpCall failed ...
}
```
Then the `setBuffer(WasmBufferType::HttpRequestBody, 0, request_body.size(), response_body)` inside the `httpCall` callback fails with BadRequest. And if I try (just for testing) to do `getBufferBytes(WasmBufferType::HttpCallResponseBody, 0, body_size)->toString()` as above to grab the current HTTP POST request body from the context, then it returns the empty string, which is strange. However, I have already set the current stream context via `getContext(stream_context_id)->setEffectiveContext();`, which I thought would allow me to do the above, and get/update the body.
Am I doing something wrong here? Any help would be much appreciated, as I cannot seem to find anything similar in the very few examples or unit tests that are around (I have only seen examples where the `httpCall` callback is updating headers, but here I want to update the body of the request). Thanks a ton!
Contributor guide
Research direction
Start by tracing the onRequestBody entry point, the root-context httpCall callback, setEffectiveContext(), and the setBuffer/getBufferBytes operations shown in the report. Read the WASM C++ SDK examples and unit tests mentioned by the author to determine whether request-body access from an httpCall callback is supported; done means documenting or reproducing the supported behavior and identifying the relevant limitation or fix.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, wasm
- Domain
- backend, networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100