From c90c744c9de0fb4f03b80d16f45f9c2a8ae796d7 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Tue, 3 Mar 2020 20:31:41 -0800 Subject: [PATCH] wasm: add proxy_set_buffer_bytes. (#442) (#184) This function can be used to: 1. Prepend data to the buffer using proxy_set_buffer(0, 0, data); 2. Append data to the buffer using proxy_set_buffer(MAX, 0, data); 3. Replace data in the buffer using proxy_set_buffer(0, MAX, data); 4. Remove data from the buffer using proxy_set_buffer(0, MAX, ""); While there, allow using MAX in proxy_get_buffer_bytes(). Signed-off-by: Piotr Sikora --- api/wasm/cpp/proxy_wasm_api.h | 4 + api/wasm/cpp/proxy_wasm_externs.h | 2 + api/wasm/cpp/proxy_wasm_intrinsics.js | 1 + source/extensions/common/wasm/context.cc | 35 ++++++- source/extensions/common/wasm/context.h | 1 + source/extensions/common/wasm/exports.cc | 51 +++++++++- source/extensions/common/wasm/exports.h | 2 + .../common/wasm/null/wasm_api_impl.h | 6 ++ source/extensions/common/wasm/wasm.cc | 1 + .../filters/http/wasm/test_data/body_cpp.cc | 60 +++++++++--- .../filters/http/wasm/test_data/body_cpp.wasm | Bin 38389 -> 39871 bytes .../filters/http/wasm/wasm_filter_test.cc | 92 +++++++++++++++++- 12 files changed, 229 insertions(+), 26 deletions(-) diff --git a/api/wasm/cpp/proxy_wasm_api.h b/api/wasm/cpp/proxy_wasm_api.h index 074170cbde25..3cef4d84e6c3 100644 --- a/api/wasm/cpp/proxy_wasm_api.h +++ b/api/wasm/cpp/proxy_wasm_api.h @@ -728,6 +728,10 @@ inline WasmResult getBufferStatus(BufferType type, size_t* size, uint32_t* flags return proxy_get_buffer_status(type, size, flags); } +inline WasmResult setBuffer(BufferType type, size_t start, size_t length, StringView data) { + return proxy_set_buffer_bytes(type, start, length, data.data(), data.size()); +} + // HTTP inline void MakeHeaderStringPairsBuffer(const HeaderStringPairs& headers, void** buffer_ptr, diff --git a/api/wasm/cpp/proxy_wasm_externs.h b/api/wasm/cpp/proxy_wasm_externs.h index dec6dfade82d..aabb64ce070b 100644 --- a/api/wasm/cpp/proxy_wasm_externs.h +++ b/api/wasm/cpp/proxy_wasm_externs.h @@ -94,6 +94,8 @@ extern "C" WasmResult proxy_get_buffer_bytes(BufferType type, uint32_t start, ui const char** ptr, size_t* size); extern "C" WasmResult proxy_get_buffer_status(BufferType type, size_t* length_ptr, uint32_t* flags_ptr); +extern "C" WasmResult proxy_set_buffer_bytes(BufferType type, uint32_t start, uint32_t length, + const char* ptr, size_t size); // HTTP extern "C" WasmResult proxy_http_call(const char* uri_ptr, size_t uri_size, void* header_pairs_ptr, diff --git a/api/wasm/cpp/proxy_wasm_intrinsics.js b/api/wasm/cpp/proxy_wasm_intrinsics.js index cc830fa3081a..a6393ea19d90 100644 --- a/api/wasm/cpp/proxy_wasm_intrinsics.js +++ b/api/wasm/cpp/proxy_wasm_intrinsics.js @@ -23,6 +23,7 @@ mergeInto(LibraryManager.library, { proxy_remove_header_map_value: function () {}, proxy_get_buffer_bytes: function () {}, proxy_get_buffer_status: function () {}, + proxy_set_buffer_bytes: function () {}, proxy_http_call: function () {}, proxy_define_metric: function () {}, proxy_increment_metric: function () {}, diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc index dc14b943e93a..02e040066e28 100644 --- a/source/extensions/common/wasm/context.cc +++ b/source/extensions/common/wasm/context.cc @@ -817,6 +817,33 @@ const Buffer::Instance* Context::getBuffer(BufferType type) { return nullptr; } +WasmResult Context::setBuffer(BufferType type, std::function callback) { + switch (type) { + case BufferType::HttpRequestBody: + if (buffering_request_body_) { + decoder_callbacks_->modifyDecodingBuffer(callback); + } else { + callback(*request_body_buffer_); + } + return WasmResult::Ok; + case BufferType::HttpResponseBody: + if (buffering_response_body_) { + encoder_callbacks_->modifyEncodingBuffer(callback); + } else { + callback(*response_body_buffer_); + } + return WasmResult::Ok; + case BufferType::NetworkDownstreamData: + callback(*network_downstream_data_buffer_); + return WasmResult::Ok; + case BufferType::NetworkUpstreamData: + callback(*network_upstream_data_buffer_); + return WasmResult::Ok; + default: + return WasmResult::BadArgument; + } +} + // Async call via HTTP WasmResult Context::httpCall(absl::string_view cluster, const Pairs& request_headers, absl::string_view request_body, const Pairs& request_trailers, @@ -1208,9 +1235,9 @@ Http::FilterDataStatus Context::onRequestBody(bool end_of_stream) { } DeferAfterCallActions actions(this); const auto buffer = getBuffer(BufferType::HttpRequestBody); - const auto body_len = (buffer == nullptr) ? 0 : buffer->length(); + const auto buffer_length = (buffer == nullptr) ? 0 : buffer->length(); switch (wasm_ - ->on_request_body_(this, id_, static_cast(body_len), + ->on_request_body_(this, id_, static_cast(buffer_length), static_cast(end_of_stream)) .u64_) { case 0: @@ -1275,9 +1302,9 @@ Http::FilterDataStatus Context::onResponseBody(bool end_of_stream) { } DeferAfterCallActions actions(this); const auto buffer = getBuffer(BufferType::HttpResponseBody); - const auto body_len = (buffer == nullptr) ? 0 : buffer->length(); + const auto buffer_length = (buffer == nullptr) ? 0 : buffer->length(); switch (wasm_ - ->on_response_body_(this, id_, static_cast(body_len), + ->on_response_body_(this, id_, static_cast(buffer_length), static_cast(end_of_stream)) .u64_) { case 0: diff --git a/source/extensions/common/wasm/context.h b/source/extensions/common/wasm/context.h index 30d4107d8803..08a69431778f 100644 --- a/source/extensions/common/wasm/context.h +++ b/source/extensions/common/wasm/context.h @@ -266,6 +266,7 @@ class Context : public Logger::Loggable, // Buffer virtual const Buffer::Instance* getBuffer(BufferType type); + virtual WasmResult setBuffer(BufferType type, std::function callback); bool end_of_stream() { return end_of_stream_; } // HTTP diff --git a/source/extensions/common/wasm/exports.cc b/source/extensions/common/wasm/exports.cc index 0ad208b066e5..1c5f2f9629ab 100644 --- a/source/extensions/common/wasm/exports.cc +++ b/source/extensions/common/wasm/exports.cc @@ -457,22 +457,23 @@ Word get_buffer_bytes(void* raw_context, Word type, Word start, Word length, Wor return wasmResultToWord(WasmResult::NotFound); } // NB: check for overflow. - if (buffer->length() < start.u64_ + length.u64_ || start.u64_ > start.u64_ + length.u64_) { + if (start.u64_ > start.u64_ + length.u64_) { return wasmResultToWord(WasmResult::BadArgument); } uint64_t pointer = 0; void* p = nullptr; - if (length.u64_ > 0) { - p = context->wasm()->allocMemory(length.u64_, &pointer); + uint64_t written = std::min(buffer->length(), length.u64_); + if (written > 0) { + p = context->wasm()->allocMemory(written, &pointer); if (!p) { return wasmResultToWord(WasmResult::InvalidMemoryAccess); } - buffer->copyOut(start.u64_, length.u64_, p); + buffer->copyOut(start.u64_, written, p); } if (!context->wasmVm()->setWord(ptr_ptr.u64_, Word(pointer))) { return wasmResultToWord(WasmResult::InvalidMemoryAccess); } - if (!context->wasmVm()->setWord(size_ptr.u64_, Word(length.u64_))) { + if (!context->wasmVm()->setWord(size_ptr.u64_, Word(written))) { return wasmResultToWord(WasmResult::InvalidMemoryAccess); } return wasmResultToWord(WasmResult::Ok); @@ -498,6 +499,46 @@ Word get_buffer_status(void* raw_context, Word type, Word length_ptr, Word flags return wasmResultToWord(WasmResult::Ok); } +Word set_buffer_bytes(void* raw_context, Word type, Word start, Word length, Word data_ptr, + Word data_size) { + if (type.u64_ > static_cast(BufferType::MAX)) { + return wasmResultToWord(WasmResult::BadArgument); + } + auto context = WASM_CONTEXT(raw_context); + auto buffer = context->getBuffer(static_cast(type.u64_)); + if (!buffer) { + return wasmResultToWord(WasmResult::NotFound); + } + auto data = context->wasmVm()->getMemory(data_ptr.u64_, data_size.u64_); + if (!data) { + return wasmResultToWord(WasmResult::InvalidMemoryAccess); + } + WasmResult result = WasmResult::InternalFailure; + if (context->setBuffer(static_cast(type.u64_), + [start = start.u64_, length = length.u64_, data, &result](auto& buffer) { + if (start == 0) { + if (length == 0) { + buffer.prepend(data.value()); + result = WasmResult::Ok; + } else if (length >= buffer.length()) { + buffer.drain(buffer.length()); + buffer.add(data.value()); + result = WasmResult::Ok; + } else { + result = WasmResult::BadArgument; + } + } else if (start >= buffer.length()) { + buffer.add(data.value()); + result = WasmResult::Ok; + } else { + result = WasmResult::BadArgument; + } + }) != WasmResult::Ok) { + return wasmResultToWord(WasmResult::BadArgument); + } + return wasmResultToWord(result); +} + Word http_call(void* raw_context, Word uri_ptr, Word uri_size, Word header_pairs_ptr, Word header_pairs_size, Word body_ptr, Word body_size, Word trailer_pairs_ptr, Word trailer_pairs_size, Word timeout_milliseconds, Word token_ptr) { diff --git a/source/extensions/common/wasm/exports.h b/source/extensions/common/wasm/exports.h index 02d3bdd405ae..8739c474d974 100644 --- a/source/extensions/common/wasm/exports.h +++ b/source/extensions/common/wasm/exports.h @@ -38,6 +38,8 @@ Word enqueue_shared_queue(void* raw_context, Word token, Word data_ptr, Word dat Word get_buffer_bytes(void* raw_context, Word type, Word start, Word length, Word ptr_ptr, Word size_ptr); Word get_buffer_status(void* raw_context, Word type, Word length_ptr, Word flags_ptr); +Word set_buffer_bytes(void* raw_context, Word type, Word start, Word length, Word data_ptr, + Word data_size); Word add_header_map_value(void* raw_context, Word type, Word key_ptr, Word key_size, Word value_ptr, Word value_size); Word get_header_map_value(void* raw_context, Word type, Word key_ptr, Word key_size, diff --git a/source/extensions/common/wasm/null/wasm_api_impl.h b/source/extensions/common/wasm/null/wasm_api_impl.h index eaddcb66ad1e..7bbdaa161a66 100644 --- a/source/extensions/common/wasm/null/wasm_api_impl.h +++ b/source/extensions/common/wasm/null/wasm_api_impl.h @@ -135,6 +135,12 @@ inline WasmResult proxy_get_buffer_status(BufferType type, size_t* length_ptr, Exports::get_buffer_status(current_context_, WS(type), WR(length_ptr), WR(flags_ptr))); } +inline WasmResult proxy_set_buffer_bytes(BufferType type, uint64_t start, uint64_t length, + const char* data_ptr, size_t data_size) { + return wordToWasmResult(Exports::set_buffer_bytes(current_context_, WS(type), WS(start), + WS(length), WR(data_ptr), WS(data_size))); +} + // Headers/Trailers/Metadata Maps inline WasmResult proxy_add_header_map_value(HeaderMapType type, const char* key_ptr, size_t key_size, const char* value_ptr, diff --git a/source/extensions/common/wasm/wasm.cc b/source/extensions/common/wasm/wasm.cc index 00ce9f6ffb49..627bb716e7d4 100644 --- a/source/extensions/common/wasm/wasm.cc +++ b/source/extensions/common/wasm/wasm.cc @@ -186,6 +186,7 @@ void Wasm::registerCallbacks() { _REGISTER_PROXY(get_buffer_status); _REGISTER_PROXY(get_buffer_bytes); + _REGISTER_PROXY(set_buffer_bytes); _REGISTER_PROXY(http_call); diff --git a/test/extensions/filters/http/wasm/test_data/body_cpp.cc b/test/extensions/filters/http/wasm/test_data/body_cpp.cc index 74415d391db2..836c084d4c9f 100644 --- a/test/extensions/filters/http/wasm/test_data/body_cpp.cc +++ b/test/extensions/filters/http/wasm/test_data/body_cpp.cc @@ -16,8 +16,8 @@ class ExampleContext : public Context { FilterDataStatus onResponseBody(size_t body_buffer_length, bool end_of_stream) override; private: - FilterDataStatus onBody(BufferType bt, size_t bufLen, bool end); - static void logBody(BufferType bt); + FilterDataStatus onBody(BufferType type, size_t buffer_length, bool end); + static void logBody(BufferType type); std::string test_op_; int num_chunks_ = 0; @@ -34,27 +34,61 @@ FilterHeadersStatus ExampleContext::onResponseHeaders(uint32_t) { return FilterHeadersStatus::Continue; } -void ExampleContext::logBody(BufferType bt) { - size_t bufferedSize; +void ExampleContext::logBody(BufferType type) { + size_t buffered_size; uint32_t flags; - getBufferStatus(bt, &bufferedSize, &flags); - auto body = getBufferBytes(bt, 0, bufferedSize); + getBufferStatus(type, &buffered_size, &flags); + auto body = getBufferBytes(type, 0, buffered_size); logError(std::string("onRequestBody ") + std::string(body->view())); } -FilterDataStatus ExampleContext::onBody(BufferType bt, size_t bufLen, bool end) { +FilterDataStatus ExampleContext::onBody(BufferType type, size_t buffer_length, bool end_of_stream) { if (test_op_ == "ReadBody") { - auto body = getBufferBytes(bt, 0, bufLen); + auto body = getBufferBytes(type, 0, buffer_length); logError("onRequestBody " + std::string(body->view())); + } else if (test_op_ == "PrependAndAppendToBody") { + setBuffer(BufferType::HttpRequestBody, 0, 0, "prepend."); + setBuffer(BufferType::HttpRequestBody, 0xFFFFFFFF, 0, ".append"); + auto updated = getBufferBytes(BufferType::HttpRequestBody, 0, 0xFFFFFFFF); + logError("onRequestBody " + std::string(updated->view())); + + } else if (test_op_ == "ReplaceBody") { + setBuffer(BufferType::HttpRequestBody, 0, 0xFFFFFFFF, "replace"); + auto replaced = getBufferBytes(BufferType::HttpRequestBody, 0, 0xFFFFFFFF); + logError("onRequestBody " + std::string(replaced->view())); + + } else if (test_op_ == "RemoveBody") { + setBuffer(BufferType::HttpRequestBody, 0, 0xFFFFFFFF, ""); + auto erased = getBufferBytes(BufferType::HttpRequestBody, 0, 0xFFFFFFFF); + logError("onRequestBody " + std::string(erased->view())); + } else if (test_op_ == "BufferBody") { - logBody(bt); - return end ? FilterDataStatus::Continue : FilterDataStatus::StopIterationAndBuffer; + logBody(type); + return end_of_stream ? FilterDataStatus::Continue : FilterDataStatus::StopIterationAndBuffer; + + } else if (test_op_ == "PrependAndAppendToBufferedBody") { + setBuffer(BufferType::HttpRequestBody, 0, 0, "prepend."); + setBuffer(BufferType::HttpRequestBody, 0xFFFFFFFF, 0, ".append"); + logBody(type); + return end_of_stream ? FilterDataStatus::Continue : FilterDataStatus::StopIterationAndBuffer; + + } else if (test_op_ == "ReplaceBufferedBody") { + setBuffer(BufferType::HttpRequestBody, 0, 0xFFFFFFFF, "replace"); + auto replaced = getBufferBytes(BufferType::HttpRequestBody, 0, 0xFFFFFFFF); + logBody(type); + return end_of_stream ? FilterDataStatus::Continue : FilterDataStatus::StopIterationAndBuffer; + + } else if (test_op_ == "RemoveBufferedBody") { + setBuffer(BufferType::HttpRequestBody, 0, 0xFFFFFFFF, ""); + auto erased = getBufferBytes(BufferType::HttpRequestBody, 0, 0xFFFFFFFF); + logBody(type); + return end_of_stream ? FilterDataStatus::Continue : FilterDataStatus::StopIterationAndBuffer; } else if (test_op_ == "BufferTwoBodies") { - logBody(bt); + logBody(type); num_chunks_++; - if (end || num_chunks_ > 2) { + if (end_of_stream || num_chunks_ > 2) { return FilterDataStatus::Continue; } return FilterDataStatus::StopIterationAndBuffer; @@ -73,4 +107,4 @@ FilterDataStatus ExampleContext::onRequestBody(size_t body_buffer_length, bool e FilterDataStatus ExampleContext::onResponseBody(size_t body_buffer_length, bool end_of_stream) { return onBody(BufferType::HttpResponseBody, body_buffer_length, end_of_stream); -} \ No newline at end of file +} diff --git a/test/extensions/filters/http/wasm/test_data/body_cpp.wasm b/test/extensions/filters/http/wasm/test_data/body_cpp.wasm index df0a34292e50dfb068dcaa9e90fc1a6663f955f3..f74afd5be57222d7b53f4e93b413434074ddceea 100644 GIT binary patch delta 9358 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 E12&4$Hvj+t diff --git a/test/extensions/filters/http/wasm/wasm_filter_test.cc b/test/extensions/filters/http/wasm/wasm_filter_test.cc index 26de3ede73bf..e9d6e3e47e12 100644 --- a/test/extensions/filters/http/wasm/wasm_filter_test.cc +++ b/test/extensions/filters/http/wasm/wasm_filter_test.cc @@ -217,14 +217,55 @@ TEST_P(WasmHttpFilterTest, BodyRequestReadBody) { filter_->onDestroy(); } +// Script that prepends and appends to the body. +TEST_P(WasmHttpFilterTest, BodyRequestPrependAndAppendToBody) { + setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( + "{{ test_rundir }}/test/extensions/filters/http/wasm/test_data/body_cpp.wasm"))); + setupFilter(); + EXPECT_CALL(*filter_, scriptLog_(spdlog::level::err, + Eq(absl::string_view("onRequestBody prepend.hello.append")))); + Http::TestHeaderMapImpl request_headers{{":path", "/"}, + {"x-test-operation", "PrependAndAppendToBody"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + Buffer::OwnedImpl data("hello"); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); + filter_->onDestroy(); +} + +// Script that replaces the body. +TEST_P(WasmHttpFilterTest, BodyRequestReplaceBody) { + setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( + "{{ test_rundir }}/test/extensions/filters/http/wasm/test_data/body_cpp.wasm"))); + setupFilter(); + EXPECT_CALL(*filter_, + scriptLog_(spdlog::level::err, Eq(absl::string_view("onRequestBody replace")))); + Http::TestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "ReplaceBody"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + Buffer::OwnedImpl data("hello"); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); + filter_->onDestroy(); +} + +// Script that removes the body. +TEST_P(WasmHttpFilterTest, BodyRequestRemoveBody) { + setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( + "{{ test_rundir }}/test/extensions/filters/http/wasm/test_data/body_cpp.wasm"))); + setupFilter(); + EXPECT_CALL(*filter_, scriptLog_(spdlog::level::err, Eq(absl::string_view("onRequestBody ")))); + Http::TestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "RemoveBody"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + Buffer::OwnedImpl data("hello"); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); + filter_->onDestroy(); +} + // Script that buffers the body. TEST_P(WasmHttpFilterTest, BodyRequestBufferBody) { setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( "{{ test_rundir }}/test/extensions/filters/http/wasm/test_data/body_cpp.wasm"))); setupFilter(); - Http::TestHeaderMapImpl request_headers{{":path", "/"}, - {"x-test-operation", "BufferBody"}}; + Http::TestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "BufferBody"}}; EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); Buffer::OwnedImpl bufferedBody; @@ -252,8 +293,7 @@ TEST_P(WasmHttpFilterTest, BodyRequestBufferBody) { EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data3, true)); // Verify that the response still works even though we buffered the request. - Http::TestHeaderMapImpl response_headers{{":status", "200"}, - {"x-test-operation", "ReadBody"}}; + Http::TestHeaderMapImpl response_headers{{":status", "200"}, {"x-test-operation", "ReadBody"}}; EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers, false)); // Should not buffer this time EXPECT_CALL(*filter_, @@ -265,6 +305,50 @@ TEST_P(WasmHttpFilterTest, BodyRequestBufferBody) { filter_->onDestroy(); } +// Script that prepends and appends to the buffered body. +TEST_P(WasmHttpFilterTest, BodyRequestPrependAndAppendToBufferedBody) { + setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( + "{{ test_rundir }}/test/extensions/filters/http/wasm/test_data/body_cpp.wasm"))); + setupFilter(); + EXPECT_CALL(*filter_, scriptLog_(spdlog::level::err, + Eq(absl::string_view("onRequestBody prepend.hello.append")))); + Http::TestHeaderMapImpl request_headers{{":path", "/"}, + {"x-test-operation", "PrependAndAppendToBufferedBody"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + Buffer::OwnedImpl data("hello"); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); + filter_->onDestroy(); +} + +// Script that replaces the buffered body. +TEST_P(WasmHttpFilterTest, BodyRequestReplaceBufferedBody) { + setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( + "{{ test_rundir }}/test/extensions/filters/http/wasm/test_data/body_cpp.wasm"))); + setupFilter(); + EXPECT_CALL(*filter_, + scriptLog_(spdlog::level::err, Eq(absl::string_view("onRequestBody replace")))); + Http::TestHeaderMapImpl request_headers{{":path", "/"}, + {"x-test-operation", "ReplaceBufferedBody"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + Buffer::OwnedImpl data("hello"); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); + filter_->onDestroy(); +} + +// Script that removes the buffered body. +TEST_P(WasmHttpFilterTest, BodyRequestRemoveBufferedBody) { + setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( + "{{ test_rundir }}/test/extensions/filters/http/wasm/test_data/body_cpp.wasm"))); + setupFilter(); + EXPECT_CALL(*filter_, scriptLog_(spdlog::level::err, Eq(absl::string_view("onRequestBody ")))); + Http::TestHeaderMapImpl request_headers{{":path", "/"}, + {"x-test-operation", "RemoveBufferedBody"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + Buffer::OwnedImpl data("hello"); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); + filter_->onDestroy(); +} + // Script that buffers the first part of the body and streams the rest TEST_P(WasmHttpFilterTest, BodyRequestBufferThenStreamBody) { setupConfig(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(