Skip to content

Commit a0f625e

Browse files
Jing-zemartijnekenkeithmattixlum1n0uswbpcode
authored
feat: add knob to customise on{Request,Response}Headers StopIteration behavior (proxy-wasm#434) (#11)
* fix: CI branch name master -> main (proxy-wasm#398) Signed-off-by: Martijn Stevenson <mstevenson@google.com> * fix: Bump Abseil to fix Linux build issues (proxy-wasm#400) Bump Abseil to fix Linux build issues Pick up this fix: abseil/abseil-cpp#1187 Bump past Envoy to pick up another fix found in fuzz tests: proxy-wasm#399 (comment) Signed-off-by: Martijn Stevenson <mstevenson@google.com> * fix: Update cargo-raze -> crate_universe (proxy-wasm#399) - Updated platforms for crate_universe compatibility - Supports upgrade to wasmsign2 - Includes workaround for Windows path length issue Signed-off-by: Martijn Stevenson <mstevenson@google.com> * fix: Move from unavailable macos-11 to macos-13 (proxy-wasm#401) See: https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources This does not fix proxy-wasm#384, but does resurface those errors. Signed-off-by: Martijn Stevenson <mstevenson@google.com> * chore: bump Bazel from 5.2.0 to 6.5.0 (proxy-wasm#402) Bump Bazel from 5.2.0 to 6.5.0 This breaks the s390x build which relied on an external Docker image. I made some strides in fixing s390x, but it's not yet working. Deferred to proxy-wasm#405. Signed-off-by: Martijn Stevenson <mstevenson@google.com> * chore: bump rules_python and rules_fuzzing (proxy-wasm#404) Upgrade rules_python (0.34.0) and rules_fuzzing (0.5.2) This requires extracting WORKSPACE phases into more phases: - dependencies -- py_repositories() and toolchains - dependencies_python() -- pip_parse module loading - dependencies_import() -- python/fuzzing/other deps The new structure roughly matches Envoy WORKSPACE: - envoy_dependencies() - envoy_dependencies_extra() -- not needed here - envoy_python_dependencies() - envoy_dependency_imports() Signed-off-by: Martijn Stevenson <mstevenson@google.com> * Update CI to use Ubuntu 22.04 / clang 14 (proxy-wasm#408) Signed-off-by: Martijn Stevenson <mstevenson@google.com> * Update rules_rust to v0.42.1 (with Rust v1.77.2). (proxy-wasm#410) * Update rules_rust * Update rust and vendor * rust_oom -> rg_oom * Change rust version --------- Signed-off-by: Keith Mattix II <keithmattix@microsoft.com> * Update wasmtime (v24.0.0) (proxy-wasm#406) Removes Wasmtime + Windows CI because rules_rust has recently dropped Windows: https://github.com/bazelbuild/rules_rust/blob/main/docs/index.md#supported-platforms Signed-off-by: Keith Mattix II <keithmattix@microsoft.com> * fix: Upgrade deprecated artifact upload/download handlers (proxy-wasm#415) Seen on proxy-wasm#380 CI: Error: This request has been automatically failed because it uses a deprecated version of `actions/upload-artifact: v2`. Learn more: https://github.blog/changelog/2024-02-13-deprecation-notice-v1-and-v2-of-the-artifact-actions/ Signed-off-by: Martijn Stevenson <mstevenson@google.com> * bump wamr to 2.1.1 and able to consume precompiled content (proxy-wasm#380) - skip leading paddings in .aot section Signed-off-by: liang.he@intel.com <liang.he@intel.com> * compdb add the compdb support to the proxy_wasm_cpp_host (proxy-wasm#419) * compdb add the compdb support to the proxy_wasm_cpp_host Signed-off-by: wangbaiping <wbphub@gmail.com> * Fix references to prefix_wasm_api (proxy-wasm#420) Signed-off-by: Keith Mattix II <keithmattix@microsoft.com> * feat(go-sdk): add wasi hostcalls used by the Go SDK (proxy-wasm#427) The full Go sdk imports hostcalls not currently exported to the wasm module, making the wasm module fail on instantiation. Per discussion with the Go core maintainers, these functions do not need to be implemented, but they must be present. Signed-off-by: Matt Leon <mattleon@google.com> * chore: workflow runner fixes (proxy-wasm#436) Assorted changes to get workflows working again: - Update format workflows to use ubuntu-22.04 - Update windows-2019 to windows-2022 and add a missing <string> include needed to build with that - Enable manual triggering of workflows Fixes proxy-wasm#435 --------- Signed-off-by: Michael Warres <mpw@google.com> * feat: add knob to customise on{Request,Response}Headers StopIteration behavior (proxy-wasm#434) Add protected ContextBase::allow_on_headers_stop_iteration_ field that can be used by host implementations to control whether or not ContextBase propagates FilterHeaderStatus::StopIteration returned by onRequestHeaders() or onResponseHeaders() without modification. Follow-on envoyproxy/envoy#40213 adds an option in Envoy WasmFilter PluginConfig that sets the value of this field. For details, see [Envoy Wasm / Proxy-Wasm support for FilterHeadersStatus::StopIteration](https://docs.google.com/document/d/1Whd1C0k-H2NHrPOmlAqqauFz6ObSTP017juJIYyciB0/edit?usp=sharing). This PR is one part of implementing [Option B: WasmFilter config knob](https://docs.google.com/document/d/1Whd1C0k-H2NHrPOmlAqqauFz6ObSTP017juJIYyciB0/edit?tab=t.0#bookmark=id.5wxldlapsp54). Note that default behavior of proxy-wasm-cpp-host and ContextBase is unchanged. --------- Signed-off-by: Michael Warres <mpw@google.com> --------- Signed-off-by: Martijn Stevenson <mstevenson@google.com> Signed-off-by: Keith Mattix II <keithmattix@microsoft.com> Signed-off-by: liang.he@intel.com <liang.he@intel.com> Signed-off-by: wangbaiping <wbphub@gmail.com> Signed-off-by: Matt Leon <mattleon@google.com> Signed-off-by: Michael Warres <mpw@google.com> Co-authored-by: martijneken <mstevenson@google.com> Co-authored-by: Keith Mattix II <keithmattix2@gmail.com> Co-authored-by: Keith Mattix II <keithmattix@microsoft.com> Co-authored-by: liang.he <liang.he@intel.com> Co-authored-by: code <wbphub@gmail.com> Co-authored-by: Matt Leon <ml@mattleon.com> Co-authored-by: Michael Warres <mpw@google.com>
1 parent 04ef279 commit a0f625e

File tree

7 files changed

+147
-5
lines changed

7 files changed

+147
-5
lines changed

include/proxy-wasm/context.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,13 @@ class ContextBase : public RootInterface,
435435
bool destroyed_ = false;
436436
bool stream_failed_ = false; // Set true after failStream is called in case of VM failure.
437437

438+
// If true, convertVmCallResultToFilterHeadersStatus() propagates
439+
// FilterHeadersStatus::StopIteration unmodified to callers. If false, it
440+
// translates FilterHeaderStatus::StopIteration to
441+
// FilterHeadersStatus::StopAllIterationAndWatermark, which is the default
442+
// behavior for v0.2.* of the Proxy-Wasm ABI.
443+
bool allow_on_headers_stop_iteration_ = false;
444+
438445
private:
439446
// helper functions
440447
FilterHeadersStatus convertVmCallResultToFilterHeadersStatus(uint64_t result);

src/context.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,12 @@ FilterHeadersStatus ContextBase::convertVmCallResultToFilterHeadersStatus(uint64
510510
result > static_cast<uint64_t>(FilterHeadersStatus::StopAllIterationAndWatermark)) {
511511
return FilterHeadersStatus::StopAllIterationAndWatermark;
512512
}
513-
if ((wasm_->on_request_headers_abi_01_ || wasm_->on_request_headers_abi_02_) &&
514-
result == static_cast<uint64_t>(FilterHeadersStatus::StopIteration)) {
515-
// Always convert StopIteration (pause processing headers, but continue processing body)
516-
// to StopAllIterationAndWatermark (pause all processing), since the former breaks all
517-
// assumptions about HTTP processing.
513+
if (result == static_cast<uint64_t>(FilterHeadersStatus::StopIteration) &&
514+
!allow_on_headers_stop_iteration_) {
515+
// Default behavior for Proxy-Wasm 0.2.* ABI is to translate StopIteration
516+
// (pause processing headers, but continue processing body) to
517+
// StopAllIterationAndWatermark (pause all processing), as described in
518+
// https://github.com/proxy-wasm/proxy-wasm-cpp-host/issues/143.
518519
return FilterHeadersStatus::StopAllIterationAndWatermark;
519520
}
520521
return static_cast<FilterHeadersStatus>(result);

test/BUILD

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,21 @@ cc_test(
132132
],
133133
)
134134

135+
cc_test(
136+
name = "stop_iteration_test",
137+
srcs = ["stop_iteration_test.cc"],
138+
data = [
139+
"//test/test_data:stop_iteration.wasm",
140+
],
141+
linkstatic = 1,
142+
deps = [
143+
":utility_lib",
144+
"//:lib",
145+
"@com_google_googletest//:gtest",
146+
"@com_google_googletest//:gtest_main",
147+
],
148+
)
149+
135150
cc_test(
136151
name = "security_test",
137152
srcs = ["security_test.cc"],

test/stop_iteration_test.cc

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "gtest/gtest.h"
16+
#include "include/proxy-wasm/wasm.h"
17+
#include "test/utility.h"
18+
19+
namespace proxy_wasm {
20+
21+
INSTANTIATE_TEST_SUITE_P(WasmEngines, TestVm, testing::ValuesIn(getWasmEngines()),
22+
[](const testing::TestParamInfo<std::string> &info) {
23+
return info.param;
24+
});
25+
26+
// TestVm is parameterized for each engine and creates a VM on construction.
27+
TEST_P(TestVm, AllowOnHeadersStopIteration) {
28+
// Read the wasm source.
29+
auto source = readTestWasmFile("stop_iteration.wasm");
30+
ASSERT_FALSE(source.empty());
31+
32+
// Create a WasmBase and load the plugin.
33+
auto wasm = std::make_shared<TestWasm>(std::move(vm_));
34+
ASSERT_TRUE(wasm->load(source, /*allow_precompiled=*/false));
35+
ASSERT_TRUE(wasm->initialize());
36+
37+
// Create a plugin.
38+
const auto plugin = std::make_shared<PluginBase>(
39+
/*name=*/"test", /*root_id=*/"", /*vm_id=*/"",
40+
/*engine=*/wasm->wasm_vm()->getEngineName(), /*plugin_config=*/"",
41+
/*fail_open=*/false, /*key=*/"");
42+
43+
// Create root context, call onStart() and onConfigure()
44+
ContextBase *root_context = wasm->start(plugin);
45+
ASSERT_TRUE(root_context != nullptr);
46+
ASSERT_TRUE(wasm->configure(root_context, plugin));
47+
48+
auto wasm_handle = std::make_shared<WasmHandleBase>(wasm);
49+
auto plugin_handle = std::make_shared<PluginHandleBase>(wasm_handle, plugin);
50+
51+
// By default, stream context onRequestHeaders and onResponseHeaders
52+
// translates FilterHeadersStatus::StopIteration to
53+
// FilterHeadersStatus::StopAllIterationAndWatermark.
54+
{
55+
auto stream_context = TestContext(wasm.get(), root_context->id(), plugin_handle);
56+
stream_context.onCreate();
57+
EXPECT_EQ(stream_context.onRequestHeaders(/*headers=*/0, /*end_of_stream=*/false),
58+
FilterHeadersStatus::StopAllIterationAndWatermark);
59+
EXPECT_EQ(stream_context.onResponseHeaders(/*headers=*/0, /*end_of_stream=*/false),
60+
FilterHeadersStatus::StopAllIterationAndWatermark);
61+
stream_context.onDone();
62+
stream_context.onDelete();
63+
}
64+
ASSERT_FALSE(wasm->isFailed());
65+
66+
// Create a stream context that propagates FilterHeadersStatus::StopIteration.
67+
{
68+
auto stream_context = TestContext(wasm.get(), root_context->id(), plugin_handle);
69+
stream_context.set_allow_on_headers_stop_iteration(true);
70+
stream_context.onCreate();
71+
EXPECT_EQ(stream_context.onRequestHeaders(/*headers=*/0, /*end_of_stream=*/false),
72+
FilterHeadersStatus::StopIteration);
73+
EXPECT_EQ(stream_context.onResponseHeaders(/*headers=*/0, /*end_of_stream=*/false),
74+
FilterHeadersStatus::StopIteration);
75+
stream_context.onDone();
76+
stream_context.onDelete();
77+
}
78+
ASSERT_FALSE(wasm->isFailed());
79+
}
80+
81+
} // namespace proxy_wasm

test/test_data/BUILD

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,8 @@ proxy_wasm_cc_binary(
8989
name = "http_logging.wasm",
9090
srcs = ["http_logging.cc"],
9191
)
92+
93+
proxy_wasm_cc_binary(
94+
name = "stop_iteration.wasm",
95+
srcs = ["stop_iteration.cc"],
96+
)

test/test_data/stop_iteration.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "proxy_wasm_intrinsics.h"
16+
17+
class StopIterationContext : public Context {
18+
public:
19+
explicit StopIterationContext(uint32_t id, RootContext *root) : Context(id, root) {}
20+
21+
FilterHeadersStatus onRequestHeaders(uint32_t headers, bool end_of_stream) override {
22+
return FilterHeadersStatus::StopIteration;
23+
}
24+
25+
FilterHeadersStatus onResponseHeaders(uint32_t headers, bool end_of_stream) override {
26+
return FilterHeadersStatus::StopIteration;
27+
}
28+
};
29+
30+
static RegisterContextFactory register_StaticContext(CONTEXT_FACTORY(StopIterationContext),
31+
ROOT_FACTORY(RootContext));

test/utility.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ class TestContext : public ContextBase {
133133
.count();
134134
}
135135

136+
void set_allow_on_headers_stop_iteration(bool allow) { allow_on_headers_stop_iteration_ = allow; }
137+
136138
private:
137139
std::string log_;
138140
static std::string global_log_;

0 commit comments

Comments
 (0)