Skip to content

Commit f3b97c7

Browse files
committed
dym sdk: initialize in module filter after set callbacks (#43660)
Commit Message: dym sdk: initialize in module filter after set callbacks Additional Description: By this way, we can access context when creating in module filters. Risk Level: Testing: Docs Changes: Release Notes: Platform Specific Features: [Optional Runtime guard:] [Optional Fixes #Issue] [Optional Fixes commit #PR or SHA] [Optional Deprecated:] [Optional [API Considerations](https://github.com/envoyproxy/envoy/blob/main/api/review_checklist.md):] --------- Signed-off-by: wbpcode/wangbaiping <wbphub@gmail.com>
1 parent c7062dd commit f3b97c7

8 files changed

Lines changed: 196 additions & 15 deletions

File tree

source/extensions/dynamic_modules/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ envoy_cc_library(
2828
":dynamic_modules_lib",
2929
"//source/common/common:logger_lib",
3030
],
31+
alwayslink = True,
3132
)
3233

3334
go_library(

source/extensions/filters/http/dynamic_modules/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,5 @@ envoy_cc_library(
6161
"//source/extensions/dynamic_modules:dynamic_modules_lib",
6262
"//source/extensions/filters/http/common:pass_through_filter_lib",
6363
],
64+
alwayslink = True,
6465
)

source/extensions/filters/http/dynamic_modules/factory.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,13 @@ absl::StatusOr<Http::FilterFactoryCb> DynamicModuleConfigFactory::createFilterFa
4444
auto filter =
4545
std::make_shared<Envoy::Extensions::DynamicModules::HttpFilters::DynamicModuleHttpFilter>(
4646
config, config->stats_scope_->symbolTable());
47-
filter->initializeInModuleFilter();
4847
callbacks.addStreamFilter(filter);
48+
49+
// The addStreamFilter() will call the setDecoderFilterCallbacks first then
50+
// setEncoderFilterCallbacks.
51+
// We can initialize the in-module filter after we have both callbacks to ensure the in module
52+
// filter can access all the necessary information during creation.
53+
filter->initializeInModuleFilter();
4954
};
5055
}
5156

test/extensions/dynamic_modules/http/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ envoy_cc_test(
6161
rbe_pool = "6gig",
6262
deps = [
6363
"//source/common/router:string_accessor_lib",
64+
"//source/extensions/dynamic_modules:abi_impl",
6465
"//source/extensions/filters/http/dynamic_modules:abi_impl",
6566
"//source/extensions/filters/http/dynamic_modules:filter_lib",
6667
"//test/extensions/dynamic_modules:util",
@@ -78,6 +79,7 @@ envoy_cc_test(
7879
# http_mocks needs this.
7980
rbe_pool = "6gig",
8081
deps = [
82+
"//source/extensions/dynamic_modules:abi_impl",
8183
"//source/extensions/filters/http/dynamic_modules:abi_impl",
8284
"//test/common/stats:stat_test_utility_lib",
8385
"//test/mocks/http:http_mocks",
@@ -107,6 +109,8 @@ envoy_cc_test(
107109
},
108110
rbe_pool = "6gig",
109111
deps = [
112+
"//source/extensions/dynamic_modules:abi_impl",
113+
"//source/extensions/filters/http/dynamic_modules:abi_impl",
110114
"//source/extensions/filters/http/dynamic_modules:factory_registration",
111115
"//test/extensions/dynamic_modules:util",
112116
"//test/integration:http_integration_lib",

test/extensions/dynamic_modules/http/integration_test.cc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,41 @@ TEST_P(DynamicModulesIntegrationTest, BytesConfig) {
204204
upstream_request_->headers().get(Http::LowerCaseString("dog"))[0]->value().getStringView());
205205
}
206206

207+
TEST_P(DynamicModulesIntegrationTest, HeaderCallbacksOnCreation) {
208+
initializeFilter("header_callbacks_on_creation", "dog:cat", "",
209+
"type.googleapis.com/google.protobuf.StringValue");
210+
codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http"))));
211+
212+
Http::TestRequestHeaderMapImpl request_headers{{"foo", "bar"},
213+
{":method", "POST"},
214+
{":path", "/test/long/url"},
215+
{":scheme", "http"},
216+
{":authority", "host"}};
217+
Http::TestRequestTrailerMapImpl request_trailers{{"foo", "bar"}};
218+
Http::TestResponseHeaderMapImpl response_headers{{":status", "200"}, {"foo", "bar"}};
219+
Http::TestResponseTrailerMapImpl response_trailers{{"foo", "bar"}};
220+
221+
auto encoder_decoder = codec_client_->startRequest(request_headers);
222+
auto response = std::move(encoder_decoder.second);
223+
codec_client_->sendData(encoder_decoder.first, 10, false);
224+
codec_client_->sendTrailers(encoder_decoder.first, request_trailers);
225+
226+
waitForNextUpstreamRequest();
227+
// Verify that the headers are added as expected in the filter.
228+
EXPECT_EQ(
229+
"cat",
230+
upstream_request_->headers().get(Http::LowerCaseString("dog"))[0]->value().getStringView());
231+
upstream_request_->encodeHeaders(response_headers, false);
232+
upstream_request_->encodeData(10, false);
233+
upstream_request_->encodeTrailers(response_trailers);
234+
235+
ASSERT_TRUE(response->waitForEndStream());
236+
237+
// Verify the proxied request was received upstream, as expected.
238+
EXPECT_TRUE(upstream_request_->complete());
239+
EXPECT_EQ(10U, upstream_request_->bodyLength());
240+
}
241+
207242
TEST_P(DynamicModulesIntegrationTest, PerRouteConfig) {
208243
initializeFilter("per_route_config", "a", "b");
209244
codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http"))));

test/extensions/dynamic_modules/test_data/cpp/http_integration_test.cc

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,83 @@ class HeaderCallbacksConfigFactory : public HttpFilterConfigFactory {
323323

324324
REGISTER_HTTP_FILTER_CONFIG_FACTORY(HeaderCallbacksConfigFactory, "header_callbacks");
325325

326+
// -----------------------------------------------------------------------------
327+
// HeaderCallbacksOnCreation
328+
// -----------------------------------------------------------------------------
329+
330+
class HeaderCallbacksOnCreationFilter : public HttpFilter {
331+
public:
332+
HeadersStatus onRequestHeaders(HeaderMap& headers, bool end_stream) override {
333+
return HeadersStatus::Continue;
334+
}
335+
336+
BodyStatus onRequestBody(BodyBuffer& body, bool end_stream) override {
337+
return BodyStatus::Continue;
338+
}
339+
340+
TrailersStatus onRequestTrailers(HeaderMap& trailers) override {
341+
return TrailersStatus::Continue;
342+
}
343+
344+
HeadersStatus onResponseHeaders(HeaderMap& headers, bool end_stream) override {
345+
return HeadersStatus::Continue;
346+
}
347+
348+
BodyStatus onResponseBody(BodyBuffer& body, bool end_stream) override {
349+
return BodyStatus::Continue;
350+
}
351+
352+
TrailersStatus onResponseTrailers(HeaderMap& trailers) override {
353+
return TrailersStatus::Continue;
354+
}
355+
356+
void onStreamComplete() override {}
357+
};
358+
359+
class HeaderCallbacksOnCreationFilterFactory : public HttpFilterFactory {
360+
public:
361+
HeaderCallbacksOnCreationFilterFactory(std::map<std::string, std::string> headers_to_add)
362+
: headers_to_add_(std::move(headers_to_add)) {}
363+
364+
std::unique_ptr<HttpFilter> create(HttpFilterHandle& handle) override {
365+
for (const auto& [k, v] : headers_to_add_) {
366+
handle.requestHeaders().set(k, v);
367+
}
368+
return std::make_unique<HeaderCallbacksOnCreationFilter>();
369+
}
370+
371+
private:
372+
std::map<std::string, std::string> headers_to_add_;
373+
};
374+
375+
class HeaderCallbacksOnCreationConfigFactory : public HttpFilterConfigFactory {
376+
public:
377+
std::unique_ptr<HttpFilterFactory> create(HttpFilterConfigHandle& handle,
378+
absl::string_view config_view) override {
379+
std::map<std::string, std::string> headers_to_add;
380+
if (!config_view.empty()) {
381+
std::string str(config_view);
382+
size_t pos = 0;
383+
while ((pos = str.find(',')) != std::string::npos) {
384+
std::string part = str.substr(0, pos);
385+
size_t sep = part.find(':');
386+
if (sep != std::string::npos) {
387+
headers_to_add[part.substr(0, sep)] = part.substr(sep + 1);
388+
}
389+
str.erase(0, pos + 1);
390+
}
391+
size_t sep = str.find(':');
392+
if (sep != std::string::npos) {
393+
headers_to_add[str.substr(0, sep)] = str.substr(sep + 1);
394+
}
395+
}
396+
return std::make_unique<HeaderCallbacksOnCreationFilterFactory>(std::move(headers_to_add));
397+
}
398+
};
399+
400+
REGISTER_HTTP_FILTER_CONFIG_FACTORY(HeaderCallbacksOnCreationConfigFactory,
401+
"header_callbacks_on_creation");
402+
326403
// -----------------------------------------------------------------------------
327404
// PerRoute
328405
// -----------------------------------------------------------------------------

test/extensions/dynamic_modules/test_data/go/http_integration_test/http_integration_test.go

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,21 @@ import (
1616

1717
func init() {
1818
sdk.RegisterHttpFilterConfigFactories(map[string]shared.HttpFilterConfigFactory{
19-
"passthrough": &PassthroughConfigFactory{},
20-
"header_callbacks": &HeaderCallbacksConfigFactory{},
21-
"per_route_config": &PerRouteConfigFactory{},
22-
"body_callbacks": &BodyCallbacksConfigFactory{},
23-
"http_callouts": &HttpCalloutsConfigFactory{},
24-
"send_response": &SendResponseConfigFactory{},
25-
"http_filter_scheduler": &HttpFilterSchedulerConfigFactory{},
26-
"fake_external_cache": &FakeExternalCacheConfigFactory{},
27-
"stats_callbacks": &StatsCallbacksConfigFactory{},
28-
"streaming_terminal_filter": &StreamingTerminalConfigFactory{},
29-
"http_stream_basic": &HttpStreamBasicConfigFactory{},
30-
"http_stream_bidirectional": &HttpStreamBidirectionalConfigFactory{},
31-
"upstream_reset": &UpstreamResetConfigFactory{},
32-
"http_config_scheduler": &ConfigSchedulerConfigFactory{},
19+
"passthrough": &PassthroughConfigFactory{},
20+
"header_callbacks": &HeaderCallbacksConfigFactory{},
21+
"header_callbacks_on_creation": &HeaderCallbacksOnCreationConfigFactory{},
22+
"per_route_config": &PerRouteConfigFactory{},
23+
"body_callbacks": &BodyCallbacksConfigFactory{},
24+
"http_callouts": &HttpCalloutsConfigFactory{},
25+
"send_response": &SendResponseConfigFactory{},
26+
"http_filter_scheduler": &HttpFilterSchedulerConfigFactory{},
27+
"fake_external_cache": &FakeExternalCacheConfigFactory{},
28+
"stats_callbacks": &StatsCallbacksConfigFactory{},
29+
"streaming_terminal_filter": &StreamingTerminalConfigFactory{},
30+
"http_stream_basic": &HttpStreamBasicConfigFactory{},
31+
"http_stream_bidirectional": &HttpStreamBidirectionalConfigFactory{},
32+
"upstream_reset": &UpstreamResetConfigFactory{},
33+
"http_config_scheduler": &ConfigSchedulerConfigFactory{},
3334
})
3435
}
3536

@@ -178,6 +179,40 @@ type HeaderCallbacksFilter struct {
178179
resTrailersCalled bool
179180
}
180181

182+
type HeaderCallbacksOnCreationConfigFactory struct {
183+
shared.EmptyHttpFilterConfigFactory
184+
}
185+
186+
func (f *HeaderCallbacksOnCreationConfigFactory) Create(handle shared.HttpFilterConfigHandle,
187+
config []byte) (shared.HttpFilterFactory, error) {
188+
headersToAdd := make(map[string]string)
189+
str := string(config)
190+
parts := strings.Split(str, ",")
191+
for _, part := range parts {
192+
kv := strings.Split(part, ":")
193+
if len(kv) == 2 {
194+
headersToAdd[kv[0]] = kv[1]
195+
}
196+
}
197+
return &HeaderCallbacksOnCreationFilterFactory{headersToAdd: headersToAdd}, nil
198+
}
199+
200+
type HeaderCallbacksOnCreationFilterFactory struct {
201+
shared.EmptyHttpFilterFactory
202+
headersToAdd map[string]string
203+
}
204+
205+
func (f *HeaderCallbacksOnCreationFilterFactory) Create(handle shared.HttpFilterHandle) shared.HttpFilter {
206+
for k, v := range f.headersToAdd {
207+
handle.RequestHeaders().Set(k, v)
208+
}
209+
return &HeaderCallbacksOnCreationFilter{}
210+
}
211+
212+
type HeaderCallbacksOnCreationFilter struct {
213+
shared.EmptyHttpFilter
214+
}
215+
181216
func assert(cond bool, msg string) {
182217
if !cond {
183218
panic("assertion failed: " + msg)

test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ fn new_http_filter_config_fn<EC: EnvoyHttpFilterConfig, EHF: EnvoyHttpFilter>(
2525
"header_callbacks" => Some(Box::new(HeadersHttpFilterConfig {
2626
headers_to_add: String::from_utf8(config.to_owned()).unwrap(),
2727
})),
28+
"header_callbacks_on_creation" => Some(Box::new(HeaderCallbacksOnCreationConfig {
29+
headers_to_add: String::from_utf8(config.to_owned()).unwrap(),
30+
})),
2831
"per_route_config" => Some(Box::new(PerRouteFilterConfig {
2932
value: String::from_utf8(config.to_owned()).unwrap(),
3033
})),
@@ -387,6 +390,26 @@ impl Drop for HeadersHttpFilter {
387390
}
388391
}
389392

393+
struct HeaderCallbacksOnCreationConfig {
394+
headers_to_add: String,
395+
}
396+
397+
impl<EHF: EnvoyHttpFilter> HttpFilterConfig<EHF> for HeaderCallbacksOnCreationConfig {
398+
fn new_http_filter(&self, envoy: &mut EHF) -> Box<dyn HttpFilter<EHF>> {
399+
for header in self.headers_to_add.split(',') {
400+
let parts: Vec<&str> = header.split(':').collect();
401+
if parts.len() == 2 {
402+
envoy.set_request_header(parts[0], parts[1].as_bytes());
403+
}
404+
}
405+
Box::new(HeaderCallbacksOnCreationFilter {})
406+
}
407+
}
408+
409+
struct HeaderCallbacksOnCreationFilter {}
410+
411+
impl<EHF: EnvoyHttpFilter> HttpFilter<EHF> for HeaderCallbacksOnCreationFilter {}
412+
390413
struct PerRouteFilterConfig {
391414
value: String,
392415
}

0 commit comments

Comments
 (0)