router: implement new regex_rewrite route action (#10050)

Support path rewriting using regular expressions and optionally capture groups.  This PR is like #8462, but using the safe regular expression support.

Risk Level:  Medium, since it slightly modifies the existing `prefix_rewrite` code.
Testing: Unit tests are added to `test/common/router/config_impl_test.cc`, runnable with `bazel test //test/common/router:config_impl_test`
Docs Changes:  Any doc that references `prefix_rewrite` has been changed to reference `regex_rewrite` as well, if appropriate.
Release Notes:  A bullet is added to `docs/root/intro/version_history.rst` mentioning the new support.

Signed-off-by: James Hennessy <jph@us.ibm.com>

Mirrored from https://github.com/envoyproxy/envoy @ 10d40f51e3e223153d9e9286b2b784b3c2e111b8
master-ci-test
data-plane-api(CircleCI) 5 years ago
parent 1f22d0744a
commit ceeac214f1
  1. 36
      envoy/api/v2/route/route_components.proto
  2. 36
      envoy/config/route/v3/route_components.proto
  3. 26
      envoy/type/matcher/regex.proto
  4. 29
      envoy/type/matcher/v3/regex.proto

@ -535,7 +535,7 @@ message CorsPolicy {
core.RuntimeFractionalPercent shadow_enabled = 10;
}
// [#next-free-field: 32]
// [#next-free-field: 33]
message RouteAction {
enum ClusterNotFoundResponseCode {
// HTTP status code - 503 Service Unavailable.
@ -749,6 +749,10 @@ message RouteAction {
// place the original path before rewrite into the :ref:`x-envoy-original-path
// <config_http_filters_router_x-envoy-original-path>` header.
//
// Only one of *prefix_rewrite* or
// :ref:`regex_rewrite <envoy_api_field_route.RouteAction.regex_rewrite>`
// may be specified.
//
// .. attention::
//
// Pay careful attention to the use of trailing slashes in the
@ -772,6 +776,36 @@ message RouteAction {
// requests to */prefix/etc* will be stripped to */etc*.
string prefix_rewrite = 5;
// Indicates that during forwarding, portions of the path that match the
// pattern should be rewritten, even allowing the substitution of capture
// groups from the pattern into the new path as specified by the rewrite
// substitution string. This is useful to allow application paths to be
// rewritten in a way that is aware of segments with variable content like
// identifiers. The router filter will place the original path as it was
// before the rewrite into the :ref:`x-envoy-original-path
// <config_http_filters_router_x-envoy-original-path>` header.
//
// Only one of :ref:`prefix_rewrite <envoy_api_field_route.RouteAction.prefix_rewrite>`
// or *regex_rewrite* may be specified.
//
// Examples using Google's `RE2 <https://github.com/google/re2>`_ engine:
//
// * The path pattern ``^/service/([^/]+)(/.*)$`` paired with a substitution
// string of ``\2/instance/\1`` would transform ``/service/foo/v1/api``
// into ``/v1/api/instance/foo``.
//
// * The pattern ``one`` paired with a substitution string of ``two`` would
// transform ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/two/zzz``.
//
// * The pattern ``^(.*?)one(.*)$`` paired with a substitution string of
// ``\1two\2`` would replace only the first occurrence of ``one``,
// transforming path ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/one/zzz``.
//
// * The pattern ``(?i)/xxx/`` paired with a substitution string of ``/yyy/``
// would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to
// ``/aaa/yyy/bbb``.
type.matcher.RegexMatchAndSubstitute regex_rewrite = 32;
oneof host_rewrite_specifier {
// Indicates that during forwarding, the host header will be swapped with
// this value.

@ -496,7 +496,7 @@ message CorsPolicy {
core.v3.RuntimeFractionalPercent shadow_enabled = 10;
}
// [#next-free-field: 32]
// [#next-free-field: 33]
message RouteAction {
option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.route.RouteAction";
@ -722,6 +722,10 @@ message RouteAction {
// place the original path before rewrite into the :ref:`x-envoy-original-path
// <config_http_filters_router_x-envoy-original-path>` header.
//
// Only one of *prefix_rewrite* or
// :ref:`regex_rewrite <envoy_api_field_config.route.v3.RouteAction.regex_rewrite>`
// may be specified.
//
// .. attention::
//
// Pay careful attention to the use of trailing slashes in the
@ -745,6 +749,36 @@ message RouteAction {
// requests to */prefix/etc* will be stripped to */etc*.
string prefix_rewrite = 5;
// Indicates that during forwarding, portions of the path that match the
// pattern should be rewritten, even allowing the substitution of capture
// groups from the pattern into the new path as specified by the rewrite
// substitution string. This is useful to allow application paths to be
// rewritten in a way that is aware of segments with variable content like
// identifiers. The router filter will place the original path as it was
// before the rewrite into the :ref:`x-envoy-original-path
// <config_http_filters_router_x-envoy-original-path>` header.
//
// Only one of :ref:`prefix_rewrite <envoy_api_field_config.route.v3.RouteAction.prefix_rewrite>`
// or *regex_rewrite* may be specified.
//
// Examples using Google's `RE2 <https://github.com/google/re2>`_ engine:
//
// * The path pattern ``^/service/([^/]+)(/.*)$`` paired with a substitution
// string of ``\2/instance/\1`` would transform ``/service/foo/v1/api``
// into ``/v1/api/instance/foo``.
//
// * The pattern ``one`` paired with a substitution string of ``two`` would
// transform ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/two/zzz``.
//
// * The pattern ``^(.*?)one(.*)$`` paired with a substitution string of
// ``\1two\2`` would replace only the first occurrence of ``one``,
// transforming path ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/one/zzz``.
//
// * The pattern ``(?i)/xxx/`` paired with a substitution string of ``/yyy/``
// would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to
// ``/aaa/yyy/bbb``.
type.matcher.v3.RegexMatchAndSubstitute regex_rewrite = 32;
oneof host_rewrite_specifier {
// Indicates that during forwarding, the host header will be swapped with
// this value.

@ -35,3 +35,29 @@ message RegexMatcher {
// The regex match string. The string must be supported by the configured engine.
string regex = 2 [(validate.rules).string = {min_bytes: 1}];
}
// Describes how to match a string and then produce a new string using a regular
// expression and a substitution string.
message RegexMatchAndSubstitute {
// The regular expression used to find portions of a string (hereafter called
// the "subject string") that should be replaced. When a new string is
// produced during the substitution operation, the new string is initially
// the same as the subject string, but then all matches in the subject string
// are replaced by the substitution string. If replacing all matches isn't
// desired, regular expression anchors can be used to ensure a single match,
// so as to replace just one occurrence of a pattern. Capture groups can be
// used in the pattern to extract portions of the subject string, and then
// referenced in the substitution string.
RegexMatcher pattern = 1;
// The string that should be substituted into matching portions of the
// subject string during a substitution operation to produce a new string.
// Capture groups in the pattern can be referenced in the substitution
// string. Note, however, that the syntax for referring to capture groups is
// defined by the chosen regular expression engine. Google's `RE2
// <https://github.com/google/re2>`_ regular expression engine uses a
// backslash followed by the capture group number to denote a numbered
// capture group. E.g., ``\1`` refers to capture group 1, and ``\2`` refers
// to capture group 2.
string substitution = 2;
}

@ -42,3 +42,32 @@ message RegexMatcher {
// The regex match string. The string must be supported by the configured engine.
string regex = 2 [(validate.rules).string = {min_bytes: 1}];
}
// Describes how to match a string and then produce a new string using a regular
// expression and a substitution string.
message RegexMatchAndSubstitute {
option (udpa.annotations.versioning).previous_message_type =
"envoy.type.matcher.RegexMatchAndSubstitute";
// The regular expression used to find portions of a string (hereafter called
// the "subject string") that should be replaced. When a new string is
// produced during the substitution operation, the new string is initially
// the same as the subject string, but then all matches in the subject string
// are replaced by the substitution string. If replacing all matches isn't
// desired, regular expression anchors can be used to ensure a single match,
// so as to replace just one occurrence of a pattern. Capture groups can be
// used in the pattern to extract portions of the subject string, and then
// referenced in the substitution string.
RegexMatcher pattern = 1;
// The string that should be substituted into matching portions of the
// subject string during a substitution operation to produce a new string.
// Capture groups in the pattern can be referenced in the substitution
// string. Note, however, that the syntax for referring to capture groups is
// defined by the chosen regular expression engine. Google's `RE2
// <https://github.com/google/re2>`_ regular expression engine uses a
// backslash followed by the capture group number to denote a numbered
// capture group. E.g., ``\1`` refers to capture group 1, and ``\2`` refers
// to capture group 2.
string substitution = 2;
}

Loading…
Cancel
Save