Skip to content

Commit b6f9a6b

Browse files
authored
[bp/1.37] dym: fix a bug where part of body maynot be sent to upstream (#44081) (#44083)
Commit Message: dym: fix a bug where part of body maynot be sent to upstream Additional Description: I have provided two different ABIs (buffered body and received body) to access buffered or latest received body. The the previous legacy addDecodedData and addEncodedData have been unnecessary. Risk Level: low. Testing: unit. Docs Changes: n/a. Release Notes: added. Platform Specific Features: n/a. [Optional Fixes #Issue] To close #43063 --------- Signed-off-by: wbpcode/wangbaiping <wbphub@gmail.com>
1 parent be7a0ac commit b6f9a6b

4 files changed

Lines changed: 61 additions & 18 deletions

File tree

changelogs/current.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ bug_fixes:
1212
change: |
1313
Fixed segfault from timer thread-safety violation, a ring buffer overflow and alpha calculation in
1414
peak_ewma loadbalancer.
15+
- area: dynamic_modules
16+
change: |
17+
Fixed a bug where dynamic module filter may result in a incomplete body being sent to upstream
18+
or downstream when some filters before or after the dynamic module filter in the chain
19+
buffered the body and the dynamic module filter did not.
1520
1621
removed_config_or_runtime:
1722
# *Normally occurs at the end of the* :ref:`deprecation period <deprecated>`

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

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,6 @@ FilterHeadersStatus DynamicModuleHttpFilter::decodeHeaders(RequestHeaderMap&, bo
8181
};
8282

8383
FilterDataStatus DynamicModuleHttpFilter::decodeData(Buffer::Instance& chunk, bool end_of_stream) {
84-
if (end_of_stream && decoder_callbacks_->decodingBuffer()) {
85-
// To make the very last chunk of the body available to the filter when buffering is enabled,
86-
// we need to call addDecodedData. See the code comment there for more details.
87-
decoder_callbacks_->addDecodedData(chunk, false);
88-
}
8984
current_request_body_ = &chunk;
9085
const envoy_dynamic_module_type_on_http_filter_request_body_status status =
9186
config_->on_http_filter_request_body_(thisAsVoidPtr(), in_module_filter_, end_of_stream);
@@ -129,11 +124,6 @@ FilterDataStatus DynamicModuleHttpFilter::encodeData(Buffer::Instance& chunk, bo
129124
if (sent_local_reply_) { // See the comment on the flag.
130125
return FilterDataStatus::Continue;
131126
}
132-
if (end_of_stream && encoder_callbacks_->encodingBuffer()) {
133-
// To make the very last chunk of the body available to the filter when buffering is enabled,
134-
// we need to call addEncodedData. See the code comment there for more details.
135-
encoder_callbacks_->addEncodedData(chunk, false);
136-
}
137127
current_response_body_ = &chunk;
138128
const envoy_dynamic_module_type_on_http_filter_response_body_status status =
139129
config_->on_http_filter_response_body_(thisAsVoidPtr(), in_module_filter_, end_of_stream);

test/extensions/dynamic_modules/http/filter_test.cc

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,62 @@ TEST_P(DynamicModuleHttpLanguageTests, FilterStateCallbacks) {
440440
EXPECT_EQ(stream_complete_value->serializeAsString(), "stream_complete_value");
441441
}
442442

443+
TEST_P(DynamicModuleTestLanguages, WillNotMoveDataAutomatically) {
444+
const std::string filter_name = "foo";
445+
const std::string filter_config = "bar";
446+
447+
const auto language = GetParam();
448+
auto dynamic_module = newDynamicModule(testSharedObjectPath("no_op", language), false);
449+
EXPECT_TRUE(dynamic_module.ok());
450+
451+
NiceMock<Server::Configuration::MockServerFactoryContext> context;
452+
Stats::IsolatedStoreImpl stats_store;
453+
auto filter_config_or_status =
454+
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
455+
filter_name, filter_config, false, std::move(dynamic_module.value()),
456+
*stats_store.createScope(""), context);
457+
EXPECT_TRUE(filter_config_or_status.ok());
458+
459+
auto filter = std::make_shared<DynamicModuleHttpFilter>(filter_config_or_status.value(),
460+
stats_store.symbolTable());
461+
filter->initializeInModuleFilter();
462+
463+
NiceMock<Http::MockStreamDecoderFilterCallbacks> decoder_callbacks;
464+
filter->setDecoderFilterCallbacks(decoder_callbacks);
465+
NiceMock<Http::MockStreamEncoderFilterCallbacks> encoder_callbacks;
466+
filter->setEncoderFilterCallbacks(encoder_callbacks);
467+
468+
TestRequestHeaderMapImpl headers{{}};
469+
EXPECT_EQ(FilterHeadersStatus::Continue, filter->decodeHeaders(headers, false));
470+
471+
Buffer::OwnedImpl buffered_request_data("buffered data");
472+
EXPECT_CALL(decoder_callbacks, addDecodedData(_, _)).Times(0); // should not be called.
473+
474+
Buffer::OwnedImpl new_request_data1("new data 1"); // 10 bytes
475+
EXPECT_EQ(FilterDataStatus::Continue, filter->decodeData(new_request_data1, false));
476+
EXPECT_EQ(10U, new_request_data1.length());
477+
Buffer::OwnedImpl new_request_data2("new data 2"); // 10 bytes
478+
EXPECT_EQ(FilterDataStatus::Continue, filter->decodeData(new_request_data2, true));
479+
EXPECT_EQ(10U, new_request_data2.length());
480+
481+
// Complete response lifecycle (needed for Rust no_op module lifecycle assertions).
482+
TestResponseHeaderMapImpl response_headers{{}};
483+
EXPECT_EQ(FilterHeadersStatus::Continue, filter->encodeHeaders(response_headers, false));
484+
485+
Buffer::OwnedImpl buffered_response_data("buffered data");
486+
EXPECT_CALL(encoder_callbacks, addEncodedData(_, _)).Times(0); // should not be called.
487+
488+
Buffer::OwnedImpl new_response_data1("new data 1"); // 10 bytes
489+
EXPECT_EQ(FilterDataStatus::Continue, filter->encodeData(new_response_data1, false));
490+
EXPECT_EQ(10U, new_response_data1.length());
491+
Buffer::OwnedImpl new_response_data2("new data 2"); // 10 bytes
492+
EXPECT_EQ(FilterDataStatus::Continue, filter->encodeData(new_response_data2, true));
493+
EXPECT_EQ(10U, new_response_data2.length());
494+
495+
filter->onStreamComplete();
496+
filter->onDestroy();
497+
}
498+
443499
TEST_P(DynamicModuleHttpLanguageTests, BodyCallbacks) {
444500
const std::string filter_name = "body_callbacks";
445501
const std::string filter_config = "";
@@ -469,12 +525,8 @@ TEST_P(DynamicModuleHttpLanguageTests, BodyCallbacks) {
469525
filter->setEncoderFilterCallbacks(encoder_callbacks);
470526
Buffer::OwnedImpl request_body;
471527
EXPECT_CALL(decoder_callbacks, decodingBuffer()).WillRepeatedly(testing::Return(&request_body));
472-
EXPECT_CALL(decoder_callbacks, addDecodedData(_, _))
473-
.WillOnce(Invoke([&](Buffer::Instance&, bool) -> void {}));
474528
Buffer::OwnedImpl response_body;
475529
EXPECT_CALL(encoder_callbacks, encodingBuffer()).WillRepeatedly(testing::Return(&response_body));
476-
EXPECT_CALL(encoder_callbacks, addEncodedData(_, _))
477-
.WillOnce(Invoke([&](Buffer::Instance&, bool) -> void {}));
478530
EXPECT_CALL(decoder_callbacks, modifyDecodingBuffer(_))
479531
.WillRepeatedly(Invoke([&](std::function<void(Buffer::Instance&)> callback) -> void {
480532
callback(request_body);

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,7 @@ struct NopHttpFilter {
9494
impl Drop for NopHttpFilter {
9595
fn drop(&mut self) {
9696
assert!(self.on_request_headers_called);
97-
assert!(self.on_request_body_called);
98-
assert!(self.on_request_trailers_called);
9997
assert!(self.on_response_headers_called);
100-
assert!(self.on_response_body_called);
101-
assert!(self.on_response_trailers_called);
10298
assert!(self.on_stream_complete_called);
10399
}
104100
}

0 commit comments

Comments
 (0)