-
Notifications
You must be signed in to change notification settings - Fork 5.3k
ext_proc: support HeaderAppendAction in mutation utils #37139
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -161,20 +161,66 @@ absl::Status MutationUtils::applyHeaderMutations(const HeaderMutation& mutation, | |
| rejected_mutations.inc(); | ||
| return absl::InvalidArgumentError("Invalid character in set_headers mutation."); | ||
| } | ||
|
|
||
| auto check_op = CheckOperation::SET; | ||
| auto should_append = false; | ||
| const LowerCaseString header_name(sh.header().key()); | ||
| const bool append = PROTOBUF_GET_WRAPPED_OR_DEFAULT(sh, append, false); | ||
| const auto check_op = (append && !headers.get(header_name).empty()) ? CheckOperation::APPEND | ||
| : CheckOperation::SET; | ||
| auto check_result = checker.check(check_op, header_name, header_value); | ||
| if (replacing_message && header_name == Http::Headers::get().Method) { | ||
| // Special handling to allow changing ":method" when the | ||
| // CONTINUE_AND_REPLACE option is selected, to stay compatible. | ||
| check_result = CheckResult::OK; | ||
| const auto header_exists = !headers.get(header_name).empty(); | ||
|
|
||
| if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.ext_proc_legacy_append")) { | ||
| // Legacy append behavior | ||
| should_append = PROTOBUF_GET_WRAPPED_OR_DEFAULT(sh, append, false); | ||
| check_op = (should_append && header_exists) ? CheckOperation::APPEND : CheckOperation::SET; | ||
| } else { | ||
| if (sh.has_append()) { | ||
| // 'append' is set and ensure the 'append_action' value is equal to the default value. | ||
| if (sh.append_action() != | ||
| envoy::config::core::v3::HeaderValueOption::APPEND_IF_EXISTS_OR_ADD) { | ||
| return absl::InvalidArgumentError( | ||
| "Both append and append_action are set and it's not allowed"); | ||
| } | ||
|
|
||
| // Legacy append behavior | ||
| should_append = sh.append().value(); | ||
| check_op = (should_append && header_exists) ? CheckOperation::APPEND : CheckOperation::SET; | ||
| } else { | ||
| switch (sh.append_action()) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of doing this inline this function, please add two helper functions to make it easy to read, like parseAppendConfig(), parseAppendActionConfig().
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I can do that. Before I start making changes, are you okay with the proposal here? |
||
| PANIC_ON_PROTO_ENUM_SENTINEL_VALUES; | ||
| case envoy::config::core::v3::HeaderValueOption::APPEND_IF_EXISTS_OR_ADD: | ||
| should_append = true; | ||
| check_op = CheckOperation::APPEND; | ||
| break; | ||
| case envoy::config::core::v3::HeaderValueOption::ADD_IF_ABSENT: | ||
| if (header_exists) { | ||
| continue; // Skip if header exists | ||
| } | ||
| should_append = false; | ||
| check_op = CheckOperation::SET; | ||
| break; | ||
| case envoy::config::core::v3::HeaderValueOption::OVERWRITE_IF_EXISTS: | ||
| if (!header_exists) { | ||
| continue; // Skip if header doesn't exist | ||
| } | ||
| should_append = false; | ||
| check_op = CheckOperation::SET; | ||
| break; | ||
| case envoy::config::core::v3::HeaderValueOption::OVERWRITE_IF_EXISTS_OR_ADD: | ||
| should_append = false; | ||
| check_op = CheckOperation::SET; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| switch (check_result) { | ||
|
|
||
| const auto check_result = checker.check(check_op, header_name, header_value); | ||
| const auto final_result = replacing_message && header_name == Http::Headers::get().Method | ||
| ? CheckResult::OK | ||
| : check_result; | ||
|
|
||
| switch (final_result) { | ||
| case CheckResult::OK: | ||
| ENVOY_LOG(trace, "Setting header {} append = {}", sh.header().key(), append); | ||
| if (append) { | ||
| ENVOY_LOG(trace, "Setting header {} append = {}", sh.header().key(), should_append); | ||
| if (should_append) { | ||
| headers.addCopy(header_name, header_value); | ||
| } else { | ||
| headers.setCopy(header_name, header_value); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
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.
Thanks for working on this issue. If we want to support both append and append_action, can we first define the behavior. I have a few questions:
Let's add comments here to clearly document it.
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.
Thanks for reviewing this! Let me address your questions in order:
appendandappend_action. Additionally, a behavior change notice is included to inform users that if neither option is explicitly set, the default behavior ofappend_actionwill apply, which is to append the header instead of replacing it.InvalidArgumentError.appendis being marked as deprecated.appendwas left unspecified or explicitly set tofalse. As a result, a minor behavior change is necessary. This is also noted as part of the changelog.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.
Agreed with below:
However, I have questions in the case both are default:
i) With the existing behavior, which only honor config "append", it will take append = false, and replace the existing headers.
ii) With your proposal, it will take append_action = APPEND_IF_EXISTS_OR_ADD, which will append.
This is not backward-compatible. Needs some more analysis on it's impact.
Another thought is if both are default, can you just take append = false, which will be backward-compatible. Then you will be able to support append-action at same time maintain backward compatibility. If in the future, there is a real need to honor append-action when both are default, you can raise a breaking-change PR then. WDYT?
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.
@yanjunxiang-google How should I distinguish that
append_actionis explicitly set toAPPEND_IF_EXISTS_OR_ADDor is not present? There is nohas_append_action()for enums.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.
That's a good question. Let me loop in @adisuissa to see whether he has some ideas on 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.
@agrawroh Here are my previous replies and opinion about breaking change and non-breaking change
breaking change (i.e. no has function for enum): #29862 (comment)
non-breaking change idea: #29862 (comment)
I have not looked at this specific code area for a quite a while, but i just want to share them for your reference