Skip to content

Commit e2ec773

Browse files
krinkinmuphlax
authored andcommitted
wasm: prevent stuck connections in case of multiple local replies (#36809)
Commit Message: This change fixes envoyproxy/envoy#28826. Some additional discussions for context can be found in proxy-wasm/proxy-wasm-cpp-host#423. The issue reported in envoyproxy/envoy#28826 happens when proxy-wasm plugin calls proxy_send_local_response during the HTTP request proessing and HTTP response processing. This happens because in attempt to mitigate a use-after-free issue (see envoyproxy/envoy#23049) we added logic to proxy-wasm that avoids calling sendLocalReply multiple times. So now when proxy-wasm plugin calls proxy_send_local_response only the first call will result in sendLocalReply, while all subsequent calls will get ignored. At the same time, when proxy-wasm plugins call proxy_send_local_response, because it's used to report an error in the plugin, proxy-wasm also stops iteration. During HTTP request processing this leads to the following chain of events: 1. During request proxy-wasm plugin calls proxy_send_local_response 2. proxy_send_local_response calls sendLocalReply, which schedules the local reply to be processed later through the filter chain 3. Request processing filter chain gets aborted and Envoy sends the previous created local reply though the filter chain 4. Proxy-wasm plugin gets called to process the response it generated and it calls proxy_send_local_response 5. proxy_send_local_response **does not** call sendLocalReply, because proxy-wasm prevents multiple calls to sendLocalReply currently 6. proxy-wasm stops iteration So in the end the filter chain iteration is stopped for the response and because proxy_send_local_respose does not actually call sendLocalReply we don't send another locally generated response either. I think we can do slightly better and close the connection in this case. This change includes the following parts: 1. Partial rollback of envoyproxy/envoy#23049 2. Tests covering this case and some other using the actual FilterManager. The most important question is why rolling back envoyproxy/envoy#23049 now is safe? The reason why it's safe, is that since introduction of prepareLocalReplyViaFilterChain in envoyproxy/envoy#24367, calling sendLocalReply multiple times is safe - that PR basically address the issue in a generic way for all the plugins, so a proxy-wasm specific fix is not needed anymore. On top of being safe, there are additional benefits to making this change: 1. We don't end up with a stuck connection in case of errors, which is slightly better 2. We remove a failure mode from proxy_send_local_response that was introduced in envoyproxy/envoy#23049 - which is good, because proxy-wasm plugins don't have a good fallback when proxy_send_local_response is failing. Finally, why replace the current mocks with a real FilterManager? Mock implementation of sendLocalReply works fine for tests that just need to assert that sendLocalReply gets called. However, in this case we rely on the fact that it's safe to call sendLocalReply multiple times and it will do the right thing and we want to assert that the connection will get closed in the end - that cannot be tested by just checking that the sendLocalReply gets called or by relying on a simplistic mock implementation of sendLocalReply. Additional Description: Risk Level: low Testing: Manually, by reproducing the case reported in envoyproxy/envoy#28826. I also added new unit tests and verified that they pass and aren't flaky: ``` bazel test --runs_per_test=1000 //test/extensions/common/wasm:all --config=docker-clang ``` Docs Changes: N/A Release Notes: N/A Platform Specific Features: N/A Fixes #28826 --------- Signed-off-by: Mikhail Krinkin <[email protected]>
1 parent ce9bce8 commit e2ec773

File tree

6 files changed

+185
-57
lines changed

6 files changed

+185
-57
lines changed

source/extensions/common/wasm/context.cc

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,12 +1598,6 @@ void Context::failStream(WasmStreamType stream_type) {
15981598
WasmResult Context::sendLocalResponse(uint32_t response_code, std::string_view body_text,
15991599
Pairs additional_headers, uint32_t grpc_status,
16001600
std::string_view details) {
1601-
// This flag is used to avoid calling sendLocalReply() twice, even if wasm code has this
1602-
// logic. We can't reuse "local_reply_sent_" here because it can't avoid calling nested
1603-
// sendLocalReply() during encodeHeaders().
1604-
if (local_reply_hold_) {
1605-
return WasmResult::BadArgument;
1606-
}
16071601
// "additional_headers" is a collection of string_views. These will no longer
16081602
// be valid when "modify_headers" is finally called below, so we must
16091603
// make copies of all the headers.
@@ -1628,11 +1622,6 @@ WasmResult Context::sendLocalResponse(uint32_t response_code, std::string_view b
16281622
modify_headers = std::move(modify_headers), grpc_status,
16291623
details = StringUtil::replaceAllEmptySpace(
16301624
absl::string_view(details.data(), details.size()))] {
1631-
// When the wasm vm fails, failStream() is called if the plugin is fail-closed, we need
1632-
// this flag to avoid calling sendLocalReply() twice.
1633-
if (local_reply_sent_) {
1634-
return;
1635-
}
16361625
// C++, Rust and other SDKs use -1 (InvalidCode) as the default value if gRPC code is not set,
16371626
// which should be mapped to nullopt in Envoy to prevent it from sending a grpc-status trailer
16381627
// at all.
@@ -1643,10 +1632,8 @@ WasmResult Context::sendLocalResponse(uint32_t response_code, std::string_view b
16431632
}
16441633
decoder_callbacks_->sendLocalReply(static_cast<Envoy::Http::Code>(response_code), body_text,
16451634
modify_headers, grpc_status_code, details);
1646-
local_reply_sent_ = true;
16471635
});
16481636
}
1649-
local_reply_hold_ = true;
16501637
return WasmResult::Ok;
16511638
}
16521639

source/extensions/common/wasm/context.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,6 @@ class Context : public proxy_wasm::ContextBase,
439439
bool buffering_response_body_ = false;
440440
bool end_of_stream_ = false;
441441
bool local_reply_sent_ = false;
442-
bool local_reply_hold_ = false;
443442
ProtobufWkt::Struct temporary_metadata_;
444443

445444
// MB: must be a node-type map as we take persistent references to the entries.

test/extensions/common/wasm/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ envoy_cc_test(
5656
"//test/extensions/common/wasm/test_data:test_context_cpp_plugin",
5757
"//test/extensions/common/wasm/test_data:test_cpp_plugin",
5858
"//test/extensions/common/wasm/test_data:test_restriction_cpp_plugin",
59+
"//test/mocks/local_reply:local_reply_mocks",
5960
"//test/mocks/server:server_mocks",
6061
"//test/test_common:environment_lib",
6162
"//test/test_common:registry_lib",

test/extensions/common/wasm/test_data/test_context_cpp.cc

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,22 +94,59 @@ FilterDataStatus DupReplyContext::onRequestBody(size_t, bool) {
9494
return FilterDataStatus::Continue;
9595
}
9696

97-
class PanicReplyContext : public Context {
97+
class LocalReplyInRequestAndResponseContext : public Context {
9898
public:
99-
explicit PanicReplyContext(uint32_t id, RootContext* root) : Context(id, root) {}
99+
explicit LocalReplyInRequestAndResponseContext(uint32_t id, RootContext* root) : Context(id, root) {}
100+
FilterHeadersStatus onRequestHeaders(uint32_t, bool) override;
101+
FilterHeadersStatus onResponseHeaders(uint32_t, bool) override;
102+
private:
103+
EnvoyRootContext* root() { return static_cast<EnvoyRootContext*>(Context::root()); }
104+
};
105+
106+
FilterHeadersStatus LocalReplyInRequestAndResponseContext::onRequestHeaders(uint32_t, bool) {
107+
sendLocalResponse(200, "ok", "body", {});
108+
return FilterHeadersStatus::Continue;
109+
}
110+
111+
FilterHeadersStatus LocalReplyInRequestAndResponseContext::onResponseHeaders(uint32_t, bool) {
112+
sendLocalResponse(200, "ok", "body", {});
113+
return FilterHeadersStatus::Continue;
114+
}
115+
116+
class PanicInRequestContext : public Context {
117+
public:
118+
explicit PanicInRequestContext(uint32_t id, RootContext* root) : Context(id, root) {}
100119
FilterDataStatus onRequestBody(size_t body_buffer_length, bool end_of_stream) override;
101120

102121
private:
103122
EnvoyRootContext* root() { return static_cast<EnvoyRootContext*>(Context::root()); }
104123
};
105124

106-
FilterDataStatus PanicReplyContext::onRequestBody(size_t, bool) {
107-
sendLocalResponse(200, "not send", "body", {});
108-
int* badptr = nullptr;
109-
*badptr = 0; // NOLINT(clang-analyzer-core.NullDereference)
125+
FilterDataStatus PanicInRequestContext::onRequestBody(size_t, bool) {
126+
abort();
110127
return FilterDataStatus::Continue;
111128
}
112129

130+
class PanicInResponseContext : public Context {
131+
public:
132+
explicit PanicInResponseContext(uint32_t id, RootContext* root) : Context(id, root) {}
133+
FilterHeadersStatus onResponseHeaders(uint32_t, bool) override;
134+
FilterHeadersStatus onRequestHeaders(uint32_t, bool) override;
135+
136+
private:
137+
EnvoyRootContext* root() { return static_cast<EnvoyRootContext*>(Context::root()); }
138+
};
139+
140+
FilterHeadersStatus PanicInResponseContext::onRequestHeaders(uint32_t, bool) {
141+
sendLocalResponse(200, "ok", "body", {});
142+
return FilterHeadersStatus::Continue;
143+
}
144+
145+
FilterHeadersStatus PanicInResponseContext::onResponseHeaders(uint32_t, bool) {
146+
abort();
147+
return FilterHeadersStatus::Continue;
148+
}
149+
113150
class InvalidGrpcStatusReplyContext : public Context {
114151
public:
115152
explicit InvalidGrpcStatusReplyContext(uint32_t id, RootContext* root) : Context(id, root) {}
@@ -128,9 +165,15 @@ FilterDataStatus InvalidGrpcStatusReplyContext::onRequestBody(size_t size, bool)
128165
static RegisterContextFactory register_DupReplyContext(CONTEXT_FACTORY(DupReplyContext),
129166
ROOT_FACTORY(EnvoyRootContext),
130167
"send local reply twice");
131-
static RegisterContextFactory register_PanicReplyContext(CONTEXT_FACTORY(PanicReplyContext),
168+
static RegisterContextFactory register_LocalReplyInRequestAndResponseContext(CONTEXT_FACTORY(LocalReplyInRequestAndResponseContext),
169+
ROOT_FACTORY(EnvoyRootContext),
170+
"local reply in request and response");
171+
static RegisterContextFactory register_PanicInRequestContext(CONTEXT_FACTORY(PanicInRequestContext),
172+
ROOT_FACTORY(EnvoyRootContext),
173+
"panic during request processing");
174+
static RegisterContextFactory register_PanicInResponseContext(CONTEXT_FACTORY(PanicInResponseContext),
132175
ROOT_FACTORY(EnvoyRootContext),
133-
"panic after sending local reply");
176+
"panic during response processing");
134177

135178
static RegisterContextFactory
136179
register_InvalidGrpcStatusReplyContext(CONTEXT_FACTORY(InvalidGrpcStatusReplyContext),

test/extensions/common/wasm/wasm_test.cc

Lines changed: 129 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
#include "envoy/http/filter.h"
2+
#include "envoy/http/filter_factory.h"
13
#include "envoy/server/lifecycle_notifier.h"
24

35
#include "source/common/common/base64.h"
46
#include "source/common/common/hex.h"
57
#include "source/common/event/dispatcher_impl.h"
8+
#include "source/common/http/filter_manager.h"
69
#include "source/common/stats/isolated_store_impl.h"
710
#include "source/extensions/common/wasm/wasm.h"
811

912
#include "test/extensions/common/wasm/wasm_runtime.h"
13+
#include "test/mocks/local_reply/mocks.h"
1014
#include "test/mocks/server/mocks.h"
1115
#include "test/mocks/stats/mocks.h"
1216
#include "test/mocks/upstream/mocks.h"
@@ -1313,7 +1317,6 @@ class WasmCommonContextTest : public Common::Wasm::WasmHttpFilterTestBase<
13131317
return new TestContext(wasm, plugin);
13141318
});
13151319
}
1316-
13171320
void setupContext() { setupFilterBase<TestContext>(); }
13181321

13191322
TestContext& rootContext() { return *static_cast<TestContext*>(root_context_); }
@@ -1395,43 +1398,19 @@ TEST_P(WasmCommonContextTest, EmptyContext) {
13951398
root_context_->validateConfiguration("", plugin_);
13961399
}
13971400

1398-
// test that we don't send the local reply twice, even though it's specified in the wasm code
1399-
TEST_P(WasmCommonContextTest, DuplicateLocalReply) {
1400-
std::string code;
1401-
if (std::get<0>(GetParam()) != "null") {
1402-
code = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(absl::StrCat(
1403-
"{{ test_rundir }}/test/extensions/common/wasm/test_data/test_context_cpp.wasm")));
1404-
} else {
1405-
// The name of the Null VM plugin.
1406-
code = "CommonWasmTestContextCpp";
1407-
}
1408-
EXPECT_FALSE(code.empty());
1409-
1410-
setup(code, "context", "send local reply twice");
1411-
setupContext();
1412-
EXPECT_CALL(decoder_callbacks_, encodeHeaders_(_, _))
1413-
.WillOnce([this](Http::ResponseHeaderMap&, bool) { context().onResponseHeaders(0, false); });
1414-
EXPECT_CALL(decoder_callbacks_,
1415-
sendLocalReply(Envoy::Http::Code::OK, testing::Eq("body"), _, _, testing::Eq("ok")));
1416-
1417-
// Create in-VM context.
1418-
context().onCreate();
1419-
EXPECT_EQ(proxy_wasm::FilterDataStatus::StopIterationNoBuffer, context().onRequestBody(0, false));
1420-
}
1421-
14221401
// test that we don't send the local reply twice when the wasm code panics
14231402
TEST_P(WasmCommonContextTest, LocalReplyWhenPanic) {
14241403
std::string code;
14251404
if (std::get<0>(GetParam()) != "null") {
14261405
code = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(absl::StrCat(
14271406
"{{ test_rundir }}/test/extensions/common/wasm/test_data/test_context_cpp.wasm")));
14281407
} else {
1429-
// no need test the Null VM plugin.
1408+
// Let's not cause crashes in Null VM
14301409
return;
14311410
}
14321411
EXPECT_FALSE(code.empty());
14331412

1434-
setup(code, "context", "panic after sending local reply");
1413+
setup(code, "context", "panic during request processing");
14351414
setupContext();
14361415
// In the case of VM failure, failStream is called, so we need to make sure that we don't send the
14371416
// local reply twice.
@@ -1495,6 +1474,125 @@ TEST_P(WasmCommonContextTest, ProcessValidGRPCStatusCodeAsEmptyInLocalReply) {
14951474
EXPECT_EQ(proxy_wasm::FilterDataStatus::StopIterationNoBuffer, context().onRequestBody(1, false));
14961475
}
14971476

1477+
class WasmLocalReplyTest : public WasmCommonContextTest {
1478+
public:
1479+
WasmLocalReplyTest() = default;
1480+
1481+
void setup(const std::string& code, std::string vm_configuration, std::string root_id = "") {
1482+
WasmCommonContextTest::setup(code, vm_configuration, root_id);
1483+
filter_manager_ = std::make_unique<Http::DownstreamFilterManager>(
1484+
filter_manager_callbacks_, dispatcher_, connection_, 0, nullptr, true, 10000,
1485+
filter_factory_, local_reply_, protocol_, time_source_, filter_state_, overload_manager_);
1486+
request_headers_ = Http::RequestHeaderMapPtr{
1487+
new Http::TestRequestHeaderMapImpl{{":path", "/"}, {":method", "GET"}}};
1488+
request_data_ = Envoy::Buffer::OwnedImpl("body");
1489+
}
1490+
1491+
Http::StreamFilterSharedPtr filter() { return context_; }
1492+
1493+
Http::FilterFactoryCb createWasmFilter() {
1494+
return [this](Http::FilterChainFactoryCallbacks& callbacks) {
1495+
callbacks.addStreamFilter(filter());
1496+
};
1497+
}
1498+
1499+
void setupContext() {
1500+
WasmCommonContextTest::setupContext();
1501+
ON_CALL(filter_factory_, createFilterChain(_))
1502+
.WillByDefault(Invoke([this](Http::FilterChainManager& manager) -> bool {
1503+
auto factory = createWasmFilter();
1504+
manager.applyFilterFactoryCb({}, factory);
1505+
return true;
1506+
}));
1507+
ON_CALL(filter_manager_callbacks_, requestHeaders())
1508+
.WillByDefault(Return(makeOptRef(*request_headers_)));
1509+
filter_manager_->createFilterChain();
1510+
filter_manager_->requestHeadersInitialized();
1511+
}
1512+
1513+
std::unique_ptr<Http::FilterManager> filter_manager_;
1514+
NiceMock<Http::MockFilterManagerCallbacks> filter_manager_callbacks_;
1515+
NiceMock<Event::MockDispatcher> dispatcher_;
1516+
NiceMock<Network::MockConnection> connection_;
1517+
NiceMock<Envoy::Http::MockFilterChainFactory> filter_factory_;
1518+
NiceMock<LocalReply::MockLocalReply> local_reply_;
1519+
Http::Protocol protocol_{Http::Protocol::Http2};
1520+
NiceMock<MockTimeSystem> time_source_;
1521+
StreamInfo::FilterStateSharedPtr filter_state_ =
1522+
std::make_shared<StreamInfo::FilterStateImpl>(StreamInfo::FilterState::LifeSpan::Connection);
1523+
NiceMock<Server::MockOverloadManager> overload_manager_;
1524+
Http::RequestHeaderMapPtr request_headers_;
1525+
Envoy::Buffer::OwnedImpl request_data_;
1526+
};
1527+
1528+
INSTANTIATE_TEST_SUITE_P(Runtimes, WasmLocalReplyTest,
1529+
Envoy::Extensions::Common::Wasm::runtime_and_cpp_values);
1530+
1531+
TEST_P(WasmLocalReplyTest, DuplicateLocalReply) {
1532+
std::string code;
1533+
if (std::get<0>(GetParam()) != "null") {
1534+
code = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(absl::StrCat(
1535+
"{{ test_rundir }}/test/extensions/common/wasm/test_data/test_context_cpp.wasm")));
1536+
} else {
1537+
// The name of the Null VM plugin.
1538+
code = "CommonWasmTestContextCpp";
1539+
}
1540+
EXPECT_FALSE(code.empty());
1541+
1542+
setup(code, "context", "send local reply twice");
1543+
setupContext();
1544+
1545+
// Even if sendLocalReply is called multiple times it should only generate a single
1546+
// response to the client, so encodeHeaders should only be called once
1547+
EXPECT_CALL(filter_manager_callbacks_, encodeHeaders(_, _));
1548+
EXPECT_CALL(filter_manager_callbacks_, endStream());
1549+
filter_manager_->decodeHeaders(*request_headers_, false);
1550+
filter_manager_->decodeData(request_data_, true);
1551+
filter_manager_->destroyFilters();
1552+
}
1553+
1554+
TEST_P(WasmLocalReplyTest, LocalReplyInRequestAndResponse) {
1555+
std::string code;
1556+
if (std::get<0>(GetParam()) != "null") {
1557+
code = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(absl::StrCat(
1558+
"{{ test_rundir }}/test/extensions/common/wasm/test_data/test_context_cpp.wasm")));
1559+
} else {
1560+
code = "CommonWasmTestContextCpp";
1561+
}
1562+
EXPECT_FALSE(code.empty());
1563+
1564+
setup(code, "context", "local reply in request and response");
1565+
setupContext();
1566+
1567+
EXPECT_CALL(filter_manager_callbacks_, encodeHeaders(_, _));
1568+
EXPECT_CALL(filter_manager_callbacks_, endStream());
1569+
filter_manager_->decodeHeaders(*request_headers_, false);
1570+
filter_manager_->decodeData(request_data_, true);
1571+
filter_manager_->destroyFilters();
1572+
}
1573+
1574+
TEST_P(WasmLocalReplyTest, PanicDuringResponse) {
1575+
std::string code;
1576+
if (std::get<0>(GetParam()) != "null") {
1577+
code = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(absl::StrCat(
1578+
"{{ test_rundir }}/test/extensions/common/wasm/test_data/test_context_cpp.wasm")));
1579+
} else {
1580+
// Let's not cause crashes in Null VM
1581+
return;
1582+
}
1583+
EXPECT_FALSE(code.empty());
1584+
1585+
setup(code, "context", "panic during response processing");
1586+
setupContext();
1587+
1588+
EXPECT_CALL(filter_manager_callbacks_, encodeHeaders(_, _));
1589+
EXPECT_CALL(filter_manager_callbacks_, endStream());
1590+
1591+
filter_manager_->decodeHeaders(*request_headers_, false);
1592+
filter_manager_->decodeData(request_data_, true);
1593+
filter_manager_->destroyFilters();
1594+
}
1595+
14981596
class PluginConfigTest : public testing::TestWithParam<std::tuple<std::string, std::string>> {
14991597
public:
15001598
PluginConfigTest() = default;
@@ -1548,7 +1646,7 @@ TEST_P(PluginConfigTest, FailReloadPolicy) {
15481646
const std::string plugin_config_yaml = fmt::format(
15491647
R"EOF(
15501648
name: "{}_test_wasm_reload"
1551-
root_id: "panic after sending local reply"
1649+
root_id: "panic during request processing"
15521650
failure_policy: FAIL_RELOAD
15531651
vm_config:
15541652
runtime: "envoy.wasm.runtime.{}"
@@ -1667,7 +1765,7 @@ TEST_P(PluginConfigTest, FailClosedPolicy) {
16671765
const std::string plugin_config_yaml = fmt::format(
16681766
R"EOF(
16691767
name: "{}_test_wasm_reload"
1670-
root_id: "panic after sending local reply"
1768+
root_id: "panic during request processing"
16711769
failure_policy: FAIL_CLOSED
16721770
vm_config:
16731771
runtime: "envoy.wasm.runtime.{}"
@@ -1746,7 +1844,7 @@ TEST_P(PluginConfigTest, FailUnspecifiedPolicy) {
17461844
const std::string plugin_config_yaml = fmt::format(
17471845
R"EOF(
17481846
name: "{}_test_wasm_reload"
1749-
root_id: "panic after sending local reply"
1847+
root_id: "panic during request processing"
17501848
vm_config:
17511849
runtime: "envoy.wasm.runtime.{}"
17521850
configuration:
@@ -1824,7 +1922,7 @@ TEST_P(PluginConfigTest, FailOpenPolicy) {
18241922
const std::string plugin_config_yaml = fmt::format(
18251923
R"EOF(
18261924
name: "{}_test_wasm_reload"
1827-
root_id: "panic after sending local reply"
1925+
root_id: "panic during request processing"
18281926
failure_policy: FAIL_OPEN
18291927
vm_config:
18301928
runtime: "envoy.wasm.runtime.{}"

test/test_common/wasm_base.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,12 @@ template <typename Base = testing::Test> class WasmHttpFilterTestBase : public W
142142
auto wasm = WasmTestBase<Base>::wasm_ ? WasmTestBase<Base>::wasm_->wasm().get() : nullptr;
143143
int root_context_id = wasm ? wasm->getRootContext(WasmTestBase<Base>::plugin_, false)->id() : 0;
144144
context_ =
145-
std::make_unique<TestFilter>(wasm, root_context_id, WasmTestBase<Base>::plugin_handle_);
145+
std::make_shared<TestFilter>(wasm, root_context_id, WasmTestBase<Base>::plugin_handle_);
146146
context_->setDecoderFilterCallbacks(decoder_callbacks_);
147147
context_->setEncoderFilterCallbacks(encoder_callbacks_);
148148
}
149149

150-
std::unique_ptr<Context> context_;
150+
std::shared_ptr<Context> context_;
151151
NiceMock<Http::MockStreamDecoderFilterCallbacks> decoder_callbacks_;
152152
NiceMock<Http::MockStreamEncoderFilterCallbacks> encoder_callbacks_;
153153
NiceMock<Envoy::StreamInfo::MockStreamInfo> request_stream_info_;
@@ -160,12 +160,12 @@ class WasmNetworkFilterTestBase : public WasmTestBase<Base> {
160160
auto wasm = WasmTestBase<Base>::wasm_ ? WasmTestBase<Base>::wasm_->wasm().get() : nullptr;
161161
int root_context_id = wasm ? wasm->getRootContext(WasmTestBase<Base>::plugin_, false)->id() : 0;
162162
context_ =
163-
std::make_unique<TestFilter>(wasm, root_context_id, WasmTestBase<Base>::plugin_handle_);
163+
std::make_shared<TestFilter>(wasm, root_context_id, WasmTestBase<Base>::plugin_handle_);
164164
context_->initializeReadFilterCallbacks(read_filter_callbacks_);
165165
context_->initializeWriteFilterCallbacks(write_filter_callbacks_);
166166
}
167167

168-
std::unique_ptr<Context> context_;
168+
std::shared_ptr<Context> context_;
169169
NiceMock<Network::MockReadFilterCallbacks> read_filter_callbacks_;
170170
NiceMock<Network::MockWriteFilterCallbacks> write_filter_callbacks_;
171171
};

0 commit comments

Comments
 (0)