-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid send empty body to ext_proc server if decodeData() never called #28672
Conversation
Signed-off-by: Yanjun Xiang <[email protected]>
CC @envoyproxy/api-shepherds: Your approval is needed for changes made to |
The solution is to add a bufferedData() check before sending body to ext_proc server. bufferedData() will only become valid pointer if decodeData() is every called. If no data received, and decodeData() is never called, it will be nullptr. |
Signed-off-by: Yanjun Xiang <[email protected]>
Signed-off-by: Yanjun Xiang <[email protected]>
/retest |
/assign @tyxia @yanavlasov |
…_body_add Signed-off-by: Yanjun Xiang <[email protected]>
/assign @stevenzzzz |
@@ -463,7 +463,7 @@ FilterTrailersStatus Filter::onTrailers(ProcessorState& state, Http::HeaderMap& | |||
return FilterTrailersStatus::StopIteration; | |||
} | |||
|
|||
if (!body_delivered && state.bodyMode() == ProcessingMode::BUFFERED) { | |||
if (!body_delivered && state.bufferedData() && state.bodyMode() == ProcessingMode::BUFFERED) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other utility function hasBufferedData() can not be used here since it not only check bufferedData() not nullptr, also checks the data->length >0. Using hasBufferedData() here will break the decodeData() with an empty chunk case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
QQ: I am wondering when do we need to decodeData() with an empty chunk case? What are the use cases for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bufferedData()!=nullptr
This is the crash log and crash traceback decode: |
The root cause of the issue is this: If ext_proc filter is configured to send body, and if only headers and trailers are received, no body is received by the ext_proc filter, it will send an empty boy to the ext_proc server. envoy/source/common/http/filter_manager.cc Line 426 in 522f991
So, filter_manager carefully maintain state_.latest_data_decoding_filter_ during decodeData(): envoy/source/common/http/filter_manager.cc Line 658 in 522f991
In this case, decodeData() is never called due to client is not sending data, and data is constructed by ext_proc filter itself. That leads to latest_data_decoding_filter_ is an empty pointer not pointing the ext_proc filter Thus the ASSERT failed, and crashed there. Overall, the ext_proc filter should not send data based on the ext_proc filter configuration. It should only send data if the data presents. Concept wise, this issue is similar to sending trailer when trailer is not present case : #28592 |
/assign @mattklein123 |
Kind Ping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work!
@@ -463,7 +463,7 @@ FilterTrailersStatus Filter::onTrailers(ProcessorState& state, Http::HeaderMap& | |||
return FilterTrailersStatus::StopIteration; | |||
} | |||
|
|||
if (!body_delivered && state.bodyMode() == ProcessingMode::BUFFERED) { | |||
if (!body_delivered && state.bufferedData() && state.bodyMode() == ProcessingMode::BUFFERED) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
QQ: I am wondering when do we need to decodeData() with an empty chunk case? What are the use cases for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "skipping body" approach in this PR feels like a behavior change that we can avoid by calling de/encodeData(dataMutations, false); on receiving the data mutation response from ext_server.
But no strong feelings.
@@ -463,7 +463,7 @@ FilterTrailersStatus Filter::onTrailers(ProcessorState& state, Http::HeaderMap& | |||
return FilterTrailersStatus::StopIteration; | |||
} | |||
|
|||
if (!body_delivered && state.bodyMode() == ProcessingMode::BUFFERED) { | |||
if (!body_delivered && state.bufferedData() && state.bodyMode() == ProcessingMode::BUFFERED) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bufferedData()!=nullptr
Thanks for the comments! The ext_proc behavior is now changed into "if configured as such, deliver body/trailer to the ext_proc server if they are present". |
@envoyproxy/api-shepherds PTAL |
API change is comment only. |
If decodeData() is not called, currently ext_proc filter is still possible to send an empty body to ext_proc server with
envoy/source/extensions/filters/http/ext_proc/ext_proc.cc
Line 480 in b8853df
and
envoy/source/extensions/filters/http/ext_proc/ext_proc.cc
Line 565 in b8853df
After body mutation from ext_proc server is received by ext_proc filter, it will modify the decoding buffer, which leads to an ASSERT() in filter manager
common/http/filter_manager.cc:426] assert failure: parent_.state_.latest_data_decoding_filter_ == this
The condition to trigger this ASSERT is ext_proc filter is configured to send body, but client only sends headers and trailers.
Commit Message:
Additional Description:
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:]