Skip to content

Conversation

@wbpcode
Copy link
Member

@wbpcode wbpcode commented Oct 18, 2025

Commit Message: http: new body transform filter with the substitution formatter
Additional Description:

To close #35783. There is enough context in the #35783. In short sentence, this PR add a transform filter to modify request or response headers by the substitution formatter API.

It's also possible to add body attributes to headers and refresh the routes.

Risk Level: low. New HTTP filter.
Testing: unit/integration.
Docs Changes: added.
Release Notes: added.
Platform Specific Features: n/a.

@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @adisuissa
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #41612 was opened by wbpcode.

see: more, trace.

@wbpcode
Copy link
Member Author

wbpcode commented Oct 18, 2025

cc @arkodg cc @agrawroh for you guys may care about this. cc @botengyao for this may helpful for AI traffic routing.

Signed-off-by: WangBaiping <[email protected]>
Signed-off-by: WangBaiping <[email protected]>
Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Left a few API comments

// Configuration for the transform filter. The request and response transformations are
// independent and could be configured separately.
// Only JSON body transformation is supported for now.
message TransformConfig {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: move this to be the first message as this is the filter's config.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.


// If true and the request headers are transformed, Envoy will re-evaluate the target
// cluster in the same route. Please ensure the cluster specifier in the route supports
// dynamic evaluation, e.g., ``envoy.router.cluster_specifier_plugin.matcher``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would happen if there isn't a cluster-specifier-plugin-matcher defined?
Also, please add a reference to the matcher specification.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then this field will no effect. And I added the reference there.

// to the existing body. If not set, the result of ``body_format_string`` will replace
// the existing body.
// True by default.
google.protobuf.BoolValue patch_format_string = 4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is highly coupled with body_format_string and that is optional, would it make sense to move both to an internal message?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

// NOTE the ``RQ_BODY`` and ``RS_BODY`` format specifiers can also be used here.
config.core.v3.SubstitutionFormatString body_format_string = 3;

// If set the result of ``body_format_string`` will be treated as a patch and will be merged
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean "patch"? does it imply that the format-string will be a regex and will replace subsections of the original body?
If it means that the result will be concatenated, I suggest replacing this to "replace_body" (because the default value should probably be "false"), or convert it to an enum that has "REPLACE_BODY"/"CONCATENATE_AT_END"/something-else (depending on the meaning of "patch").

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM. This is a great suggestion.

// And except the commonly used format specifiers, there are some additional format specifiers
// provided by the transform filter:
//
// * ``%RQ_BODY(X)%``: the request body. And ``X`` is the JSON pointer to extract a specific
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this require a JSON-body? I may have missed it, but this seems to be a generic transform, and doesn't require JSON-body to be sent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSON body is required. We have documented it that only JSON body is supported for now.

// * ``%RQ_BODY(X)%``: the request body. And ``X`` is the JSON pointer to extract a specific
// field from the JSON body. If ``X`` is empty, the whole body will be used.
// * ``%RS_BODY(X)%``: the response body. And ``X`` is the JSON pointer to extract a specific
// field from the JSON body. If ``X`` is empty, the whole body will be used.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the whole body will be used

FWIW this might cause the headermap to go over the limit, and may be an attack vector, but as this filter doesn't have a security posture, it might be ok.

Also it would be good to clarify whether using this filter implies that all requests/responses are buffered, even if headers_mutations are defined without referencing RQ/RS_BODY. If there's a need to support both buffering and streaming modes, consider adding an enum field specifying the mode (and maybe only support one for now).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At next few weeks, I will try to support the event stream for the response. We will handle it as stream for that. But for JSON request/response, buffering always be used.


// Body transformation configuration. If not set, no body transformation will be performed.
// NOTE the ``RQ_BODY`` and ``RS_BODY`` format specifiers can also be used here.
config.core.v3.SubstitutionFormatString body_format_string = 3;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thoughts on using JSONPatch semantics here ?
https://jsonpatch.com
its used in Envoy Gateway API to edit xDS https://gateway.envoyproxy.io/docs/tasks/extensibility/envoy-patch-policy/#customize-response

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM. But it's will have big effect to the current implementation. I will update the API to keep the patch mode as enum and then we can support it in the future.

Copy link
Member

@botengyao botengyao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for adding this filter! have one question out of curiosity.

Comment on lines +178 to +182
if (end_stream) {
decoder_callbacks_->addDecodedData(data, true);
handleCompleteRequestBody();
return Http::FilterDataStatus::Continue;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related but not tied / blocker to this PR, do you have some insights for the streaming JSON parser support without waiting for the whole body once we get the enough data. I think the current nlohmann lib doesn't quite support it, and we could need some SAX style approach.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rapidJson could help? But we removed that because suggestions from google. 🤣

@wbpcode
Copy link
Member Author

wbpcode commented Oct 28, 2025

friendly ping for a new review cc @adisuissa

@wbpcode
Copy link
Member Author

wbpcode commented Oct 29, 2025

/retest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Body Transformations

4 participants