Skip to content

Commit 140b3a2

Browse files
committed
auto-merge envoyproxy/envoy[release/v1.32] into envoyproxy/envoy-openssl[release/v1.32]
* upstream/release/v1.32: repo: Dev v1.32.7 repo: Release v1.32.6 release/docker: Bump release image -> 67cadaf (#39344) release/docker: Bump release image -> d80997d (#39198) build(deps): bump distroless/base-nossl-debian12 from nonroot@sha256:462657c8bb91f01a95cb1aabdd13d9fd2b816ac2f9fb7fe52ff07bfe50a03b38 to sha256:7eee43f73be0b403c75dddd4254cb672d7645048a9e6f1c478eadc3a415ce9bf in /ci (#39153) Remove link to a broken doc (#39170) uri_template: Add support for the "*" character matching in pattern rewrite and matching (#39169) Signed-off-by: tedjpoole <[email protected]>
2 parents 10a053f + b3c27a2 commit 140b3a2

File tree

17 files changed

+250
-49
lines changed

17 files changed

+250
-49
lines changed

VERSION.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.32.6-dev
1+
1.32.7-dev

changelogs/1.31.8.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
date: May 7, 2025
2+
3+
bug_fixes:
4+
- area: url_template
5+
change: |
6+
Included the asterisk ``*`` in the match pattern when using the * or ** operators in the URL template.
7+
This behavioral change can be temporarily reverted by setting runtime guard
8+
``envoy.reloadable_features.uri_template_match_on_asterisk`` to ``false``.

changelogs/1.32.6.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
date: May 7, 2025
2+
3+
bug_fixes:
4+
- area: url_template
5+
change: |
6+
Included the asterisk ``*`` in the match pattern when using the * or ** operators in the URL template.
7+
This behavioral change can be temporarily reverted by setting runtime guard
8+
``envoy.reloadable_features.uri_template_match_on_asterisk`` to ``false``.

ci/Dockerfile-envoy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
ARG BUILD_OS=ubuntu
22
ARG BUILD_TAG=22.04
3-
ARG BUILD_SHA=ed1544e454989078f5dec1bfdabd8c5cc9c48e0705d07b678ab6ae3fb61952d2
3+
ARG BUILD_SHA=67cadaff1dca187079fce41360d5a7eb6f7dcd3745e53c79ad5efd8563118240
44
ARG ENVOY_VRP_BASE_IMAGE=envoy-base
55

66

@@ -59,7 +59,7 @@ COPY --chown=0:0 --chmod=755 \
5959

6060

6161
# STAGE: envoy-distroless
62-
FROM gcr.io/distroless/base-nossl-debian12:nonroot@sha256:462657c8bb91f01a95cb1aabdd13d9fd2b816ac2f9fb7fe52ff07bfe50a03b38 AS envoy-distroless
62+
FROM gcr.io/distroless/base-nossl-debian12:nonroot@sha256:d1fc914c43cea489c26c896721344a49a1761b9bb678bcba1758772d22913302 AS envoy-distroless
6363
EXPOSE 10000
6464
ENTRYPOINT ["/usr/local/bin/envoy"]
6565
CMD ["-c", "/etc/envoy/envoy.yaml"]

docs/inventories/v1.31/objects.inv

32 Bytes
Binary file not shown.

docs/inventories/v1.32/objects.inv

67 Bytes
Binary file not shown.

docs/root/start/install.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ The Envoy project currently supports ``amd64`` and ``arm64`` architectures for i
110110

111111
Contrib builds
112112
^^^^^^^^^^^^^^
113-
As described in `this document <https://docs.google.com/document/d/1yl7GOZK1TDm_7vxQvt8UQEAu07UQFru1uEKXM6ZZg_g/edit#>`_,
114-
the Envoy project allows extensions to enter the repository as "contrib" extensions. The requirements
113+
Envoy project allows extensions to enter the repository as "contrib" extensions. The requirements
115114
for such extensions are lower, and as such they are only available by default in special images.
116115

117116
Throughout the documentation, extensions are clearly marked as being a contrib extension or a core extension.

docs/versions.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@
2424
"1.28": 1.28.7
2525
"1.29": 1.29.12
2626
"1.30": 1.30.11
27-
"1.31": 1.31.7
28-
"1.32": 1.32.4
27+
"1.31": 1.31.8
28+
"1.32": 1.32.5

source/common/runtime/runtime_features.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ RUNTIME_GUARD(envoy_reloadable_features_udp_set_do_not_fragment);
101101
RUNTIME_GUARD(envoy_reloadable_features_udp_socket_apply_aggregated_read_limit);
102102
RUNTIME_GUARD(envoy_reloadable_features_uhv_allow_malformed_url_encoding);
103103
RUNTIME_GUARD(envoy_reloadable_features_upstream_remote_address_use_connection);
104+
RUNTIME_GUARD(envoy_reloadable_features_uri_template_match_on_asterisk);
104105
RUNTIME_GUARD(envoy_reloadable_features_use_config_in_happy_eyeballs);
105106
RUNTIME_GUARD(envoy_reloadable_features_use_filter_manager_state_for_downstream_end_stream);
106107
RUNTIME_GUARD(envoy_reloadable_features_use_http_client_to_fetch_aws_credentials);

source/extensions/path/uri_template_lib/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ envoy_cc_library(
3535
hdrs = ["uri_template_internal.h"],
3636
deps = [
3737
"//source/common/common:fmt_lib",
38+
"//source/common/runtime:runtime_features_lib",
3839
"@com_google_absl//absl/container:flat_hash_set",
3940
"@com_google_absl//absl/flags:flag",
4041
"@com_google_absl//absl/functional:function_ref",

source/extensions/path/uri_template_lib/uri_template_internal.cc

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <vector>
88

99
#include "source/common/common/fmt.h"
10+
#include "source/common/runtime/runtime_features.h"
1011

1112
#include "absl/container/flat_hash_set.h"
1213
#include "absl/flags/flag.h"
@@ -46,6 +47,16 @@ constexpr absl::string_view kLiteral = "a-zA-Z0-9-._~" // Unreserved
4647
":@"
4748
"="; // user included "=" allowed
4849

50+
// Additional literal that allows "*" in the pattern.
51+
// This should replace "kLiteral" after removal of
52+
// "reloadable_features.uri_template_match_on_asterisk" runtime guard.
53+
// Valid pchar from https://datatracker.ietf.org/doc/html/rfc3986#appendix-A
54+
constexpr absl::string_view kLiteralWithAsterisk = "a-zA-Z0-9-._~" // Unreserved
55+
"%" // pct-encoded
56+
"!$&'()+,;" // sub-delims excluding *=
57+
":@"
58+
"=*"; // reserved characters
59+
4960
// Default operator used for the variable when none specified.
5061
constexpr Operator kDefaultVariableOperator = Operator::PathGlob;
5162

@@ -122,17 +133,30 @@ std::string ParsedPathPattern::debugString() const {
122133
}
123134

124135
bool isValidLiteral(absl::string_view literal) {
136+
static const std::string* kValidLiteralRegexAsterisk =
137+
new std::string(absl::StrCat("^[", kLiteralWithAsterisk, "]+$"));
125138
static const std::string* kValidLiteralRegex =
126139
new std::string(absl::StrCat("^[", kLiteral, "]+$"));
140+
static const LazyRE2 literal_regex_asterisk = {kValidLiteralRegexAsterisk->data()};
127141
static const LazyRE2 literal_regex = {kValidLiteralRegex->data()};
128-
return RE2::FullMatch(literal, *literal_regex);
142+
143+
return Runtime::runtimeFeatureEnabled("envoy.reloadable_features.uri_template_match_on_asterisk")
144+
? RE2::FullMatch(literal, *literal_regex_asterisk)
145+
: RE2::FullMatch(literal, *literal_regex);
129146
}
130147

131148
bool isValidRewriteLiteral(absl::string_view literal) {
132149
static const std::string* kValidLiteralRegex =
133150
new std::string(absl::StrCat("^[", kLiteral, "/]+$"));
151+
static const std::string* kValidLiteralRegexAsterisk =
152+
new std::string(absl::StrCat("^[", kLiteralWithAsterisk, "/]+$"));
153+
134154
static const LazyRE2 literal_regex = {kValidLiteralRegex->data()};
135-
return RE2::FullMatch(literal, *literal_regex);
155+
static const LazyRE2 literal_regex_asterisk = {kValidLiteralRegexAsterisk->data()};
156+
157+
return Runtime::runtimeFeatureEnabled("envoy.reloadable_features.uri_template_match_on_asterisk")
158+
? RE2::FullMatch(literal, *literal_regex_asterisk)
159+
: RE2::FullMatch(literal, *literal_regex);
136160
}
137161

138162
bool isValidVariableName(absl::string_view variable) {
@@ -360,11 +384,26 @@ std::string toRegexPattern(absl::string_view pattern) {
360384
std::string toRegexPattern(Operator pattern) {
361385
static const std::string* kPathGlobRegex = new std::string(absl::StrCat("[", kLiteral, "]+"));
362386
static const std::string* kTextGlobRegex = new std::string(absl::StrCat("[", kLiteral, "/]*"));
363-
switch (pattern) {
364-
case Operator::PathGlob: // "*"
365-
return *kPathGlobRegex;
366-
case Operator::TextGlob: // "**"
367-
return *kTextGlobRegex;
387+
388+
static const std::string* kPathGlobRegexAsterisk =
389+
new std::string(absl::StrCat("[", kLiteralWithAsterisk, "]+"));
390+
static const std::string* kTextGlobRegexAsterisk =
391+
new std::string(absl::StrCat("[", kLiteralWithAsterisk, "/]*"));
392+
393+
if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.uri_template_match_on_asterisk")) {
394+
switch (pattern) {
395+
case Operator::PathGlob: // "*"
396+
return *kPathGlobRegexAsterisk;
397+
case Operator::TextGlob: // "**"
398+
return *kTextGlobRegexAsterisk;
399+
}
400+
} else {
401+
switch (pattern) {
402+
case Operator::PathGlob: // "*"
403+
return *kPathGlobRegex;
404+
case Operator::TextGlob: // "**"
405+
return *kTextGlobRegex;
406+
}
368407
}
369408
return "";
370409
}

test/extensions/path/match/uri_template/library_test.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,66 @@ TEST(MatchTest, BasicUsage) {
4343
EXPECT_TRUE(matcher->match("/bar/en/us"));
4444
}
4545

46+
TEST(MatchTest, MatchSingleAsteriskInWildcard) {
47+
const std::string yaml_string = R"EOF(
48+
name: envoy.path.match.uri_template.uri_template_matcher
49+
typed_config:
50+
"@type": type.googleapis.com/envoy.extensions.path.match.uri_template.v3.UriTemplateMatchConfig
51+
path_template: "/bar/{lang}/{country=**}"
52+
)EOF";
53+
54+
Router::PathMatcherSharedPtr matcher = createMatcherFromYaml(yaml_string);
55+
EXPECT_EQ(matcher->uriTemplate(), "/bar/{lang}/{country=**}");
56+
EXPECT_EQ(matcher->name(), "envoy.path.match.uri_template.uri_template_matcher");
57+
58+
EXPECT_TRUE(matcher->match("/bar/en/us*"));
59+
}
60+
61+
TEST(MatchTest, MatchDoubleAsteriskInWildcard) {
62+
const std::string yaml_string = R"EOF(
63+
name: envoy.path.match.uri_template.uri_template_matcher
64+
typed_config:
65+
"@type": type.googleapis.com/envoy.extensions.path.match.uri_template.v3.UriTemplateMatchConfig
66+
path_template: "/bar/{lang}/{country=**}"
67+
)EOF";
68+
69+
Router::PathMatcherSharedPtr matcher = createMatcherFromYaml(yaml_string);
70+
EXPECT_EQ(matcher->uriTemplate(), "/bar/{lang}/{country=**}");
71+
EXPECT_EQ(matcher->name(), "envoy.path.match.uri_template.uri_template_matcher");
72+
73+
EXPECT_TRUE(matcher->match("/bar/en/us**"));
74+
}
75+
76+
TEST(MatchTest, MatchSingleAsterisk) {
77+
const std::string yaml_string = R"EOF(
78+
name: envoy.path.match.uri_template.uri_template_matcher
79+
typed_config:
80+
"@type": type.googleapis.com/envoy.extensions.path.match.uri_template.v3.UriTemplateMatchConfig
81+
path_template: "/bar/{lang}/{country=**}"
82+
)EOF";
83+
84+
Router::PathMatcherSharedPtr matcher = createMatcherFromYaml(yaml_string);
85+
EXPECT_EQ(matcher->uriTemplate(), "/bar/{lang}/{country=**}");
86+
EXPECT_EQ(matcher->name(), "envoy.path.match.uri_template.uri_template_matcher");
87+
88+
EXPECT_TRUE(matcher->match("/bar/en*/us"));
89+
}
90+
91+
TEST(MatchTest, MatchDoubleAsterisk) {
92+
const std::string yaml_string = R"EOF(
93+
name: envoy.path.match.uri_template.uri_template_matcher
94+
typed_config:
95+
"@type": type.googleapis.com/envoy.extensions.path.match.uri_template.v3.UriTemplateMatchConfig
96+
path_template: "/bar/{lang}/{country=**}"
97+
)EOF";
98+
99+
Router::PathMatcherSharedPtr matcher = createMatcherFromYaml(yaml_string);
100+
EXPECT_EQ(matcher->uriTemplate(), "/bar/{lang}/{country=**}");
101+
EXPECT_EQ(matcher->name(), "envoy.path.match.uri_template.uri_template_matcher");
102+
103+
EXPECT_TRUE(matcher->match("/bar/en**/us"));
104+
}
105+
46106
TEST(MatchTest, MatchDoubleEqualsInWildcard) {
47107
const std::string yaml_string = R"EOF(
48108
name: envoy.path.match.uri_template.uri_template_matcher

test/extensions/path/rewrite/uri_template/library_test.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,62 @@ TEST(RewriteTest, BasicUsage) {
7171
EXPECT_EQ(rewriter->name(), "envoy.path.rewrite.uri_template.uri_template_rewriter");
7272
}
7373

74+
TEST(RewriteTest, SingleAsteriskAtEndOfPath) {
75+
const std::string yaml_string = R"EOF(
76+
name: envoy.path.rewrite.uri_template.uri_template_rewriter
77+
typed_config:
78+
"@type": type.googleapis.com/envoy.extensions.path.rewrite.uri_template.v3.UriTemplateRewriteConfig
79+
path_template_rewrite: "/bar/{country}/{final}"
80+
)EOF";
81+
82+
Router::PathRewriterSharedPtr rewriter = createRewriterFromYaml(yaml_string);
83+
EXPECT_EQ(rewriter->rewritePath("/bar/usa/final*1", "/bar/{final}/{country}").value(),
84+
"/bar/final*1/usa");
85+
EXPECT_EQ(rewriter->name(), "envoy.path.rewrite.uri_template.uri_template_rewriter");
86+
}
87+
88+
TEST(RewriteTest, SingleAsterisk) {
89+
const std::string yaml_string = R"EOF(
90+
name: envoy.path.rewrite.uri_template.uri_template_rewriter
91+
typed_config:
92+
"@type": type.googleapis.com/envoy.extensions.path.rewrite.uri_template.v3.UriTemplateRewriteConfig
93+
path_template_rewrite: "/bar/{country}/final"
94+
)EOF";
95+
96+
Router::PathRewriterSharedPtr rewriter = createRewriterFromYaml(yaml_string);
97+
EXPECT_EQ(rewriter->rewritePath("/bar/usa*/final", "/bar/{country}/final").value(),
98+
"/bar/usa*/final");
99+
EXPECT_EQ(rewriter->name(), "envoy.path.rewrite.uri_template.uri_template_rewriter");
100+
}
101+
102+
TEST(RewriteTest, DoubleAsteriskAtEndOfPath) {
103+
const std::string yaml_string = R"EOF(
104+
name: envoy.path.rewrite.uri_template.uri_template_rewriter
105+
typed_config:
106+
"@type": type.googleapis.com/envoy.extensions.path.rewrite.uri_template.v3.UriTemplateRewriteConfig
107+
path_template_rewrite: "/bar/{country}/{final}"
108+
)EOF";
109+
110+
Router::PathRewriterSharedPtr rewriter = createRewriterFromYaml(yaml_string);
111+
EXPECT_EQ(rewriter->rewritePath("/bar/usa/final**1", "/bar/{final}/{country}").value(),
112+
"/bar/final**1/usa");
113+
EXPECT_EQ(rewriter->name(), "envoy.path.rewrite.uri_template.uri_template_rewriter");
114+
}
115+
116+
TEST(RewriteTest, DoubleAsterisk) {
117+
const std::string yaml_string = R"EOF(
118+
name: envoy.path.rewrite.uri_template.uri_template_rewriter
119+
typed_config:
120+
"@type": type.googleapis.com/envoy.extensions.path.rewrite.uri_template.v3.UriTemplateRewriteConfig
121+
path_template_rewrite: "/bar/{country}/final"
122+
)EOF";
123+
124+
Router::PathRewriterSharedPtr rewriter = createRewriterFromYaml(yaml_string);
125+
EXPECT_EQ(rewriter->rewritePath("/bar/usa**/final", "/bar/{country}/final").value(),
126+
"/bar/usa**/final");
127+
EXPECT_EQ(rewriter->name(), "envoy.path.rewrite.uri_template.uri_template_rewriter");
128+
}
129+
74130
TEST(RewriteTest, DoubleEqualAtEndOfPath) {
75131
const std::string yaml_string = R"EOF(
76132
name: envoy.path.rewrite.uri_template.uri_template_rewriter

test/extensions/path/uri_template_lib/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ envoy_cc_test(
3131
deps = [
3232
"//source/extensions/path/uri_template_lib:uri_template_internal_cc",
3333
"//test/test_common:status_utility_lib",
34+
"//test/test_common:test_runtime_lib",
3435
"@com_google_absl//absl/status",
3536
"@com_google_absl//absl/status:statusor",
3637
"@com_google_absl//absl/strings",

0 commit comments

Comments
 (0)