Skip to content

Commit 880e777

Browse files
shuqzzac-nixon
authored andcommitted
[feat gw-api]update behavior and doc
1 parent 70a1e53 commit 880e777

File tree

3 files changed

+13
-84
lines changed

3 files changed

+13
-84
lines changed

docs/guide/gateway/l7gateway.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,9 @@ The AWS Load Balancer Controller supports HTTPRoute RequestRedirect filters with
206206

207207
**ReplacePrefixMatch Behavior:**
208208

209-
The behavior of `ReplacePrefixMatch` depends on whether other redirect components are modified:
209+
We support `ReplacePrefixMatch` with limitations:
210210

211-
1. **With scheme/port/hostname changes** - Path suffixes are preserved:
211+
1. **With scheme/port/hostname changes** - Works as expected:
212212
```yaml
213213
filters:
214214
- type: RequestRedirect
@@ -221,7 +221,7 @@ The behavior of `ReplacePrefixMatch` depends on whether other redirect component
221221
- Request: `/old-prefix/path/to/resource`
222222
- Redirects to: `/new-prefix/path/to/resource` ✅ (suffix preserved)
223223

224-
2. **Without other component changes** - Only prefix is replaced, suffixes are NOT preserved:
224+
2. **Without other component changes** - AWS ALB will reject with redirect loop error:
225225
```yaml
226226
filters:
227227
- type: RequestRedirect
@@ -230,13 +230,14 @@ The behavior of `ReplacePrefixMatch` depends on whether other redirect component
230230
type: ReplacePrefixMatch
231231
replacePrefixMatch: /new-prefix
232232
```
233-
- Request: `/old-prefix/path/to/resource`
234-
- Redirects to: `/new-prefix` ❌ (suffix lost)
233+
- This configuration will be rejected by the API with "InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop." ❌
235234

236235
**Recommendations:**
237236

238-
- For path-only redirects with exact paths, use `ReplaceFullPath`
239-
- To preserve path suffixes with prefix replacement, also modify `scheme`, `port`, or `hostname`
237+
- For path-only redirects, use `ReplaceFullPath` instead
238+
- To use `ReplacePrefixMatch`, you must also modify `scheme`, `port`, or `hostname`
239+
240+
**Important**: If one HTTPRoute rule has an invalid redirect configuration (e.g., path-only redirect with `ReplacePrefixMatch` that cause redirect loop), the controller will fail to create that listener rule and stop processing subsequent rules in the same HTTPRoute. This means valid rules with lower precedence (shorter paths, later in the route) will not be created.
240241

241242
#### Examples
242243

pkg/gateway/routeutils/route_rule_action.go

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,6 @@ func buildHttpRuleRedirectActionsBasedOnFilter(filters []gwv1.HTTPRouteFilter, r
225225
// buildHttpRedirectAction configure filter attributes to RedirectActionConfig
226226
// gateway api has no attribute to specify query, use listener rule configuration
227227
func buildHttpRedirectAction(filter *gwv1.HTTPRequestRedirectFilter, redirectConfig *elbv2gw.RedirectActionConfig) (*elbv2model.Action, error) {
228-
isComponentSpecified := false
229228
var statusCode string
230229
if filter.StatusCode != nil {
231230
statusCodeStr := fmt.Sprintf("HTTP_%d", *filter.StatusCode)
@@ -236,7 +235,6 @@ func buildHttpRedirectAction(filter *gwv1.HTTPRequestRedirectFilter, redirectCon
236235
if filter.Port != nil {
237236
portStr := fmt.Sprintf("%d", *filter.Port)
238237
port = &portStr
239-
isComponentSpecified = true
240238
}
241239

242240
var protocol *string
@@ -246,7 +244,6 @@ func buildHttpRedirectAction(filter *gwv1.HTTPRequestRedirectFilter, redirectCon
246244
return nil, errors.Errorf("unsupported redirect scheme: %v", upperScheme)
247245
}
248246
protocol = &upperScheme
249-
isComponentSpecified = true
250247
}
251248

252249
var path *string
@@ -257,28 +254,18 @@ func buildHttpRedirectAction(filter *gwv1.HTTPRequestRedirectFilter, redirectCon
257254
return nil, errors.Errorf("ReplaceFullPath shouldn't contain wildcards: %v", pathValue)
258255
}
259256
path = filter.Path.ReplaceFullPath
260-
isComponentSpecified = true
261257
} else if filter.Path.ReplacePrefixMatch != nil {
262-
// Use #{path} if other components are modified (avoids redirect loop)
263-
// Otherwise use literal prefix (no suffix preservation)
264-
if filter.Scheme != nil || filter.Port != nil || filter.Hostname != nil {
265-
pathVariable := "/#{path}"
266-
path = &pathVariable
267-
} else {
268-
path = filter.Path.ReplacePrefixMatch
258+
//url rewrite will handle path transform
259+
pathValue := *filter.Path.ReplacePrefixMatch
260+
if strings.ContainsAny(pathValue, "*?") {
261+
return nil, errors.Errorf("ReplacePrefixMatch shouldn't contain wildcards: %v", pathValue)
269262
}
270-
isComponentSpecified = true
271263
}
272264
}
273265

274266
var hostname *string
275267
if filter.Hostname != nil {
276268
hostname = (*string)(filter.Hostname)
277-
isComponentSpecified = true
278-
}
279-
280-
if !isComponentSpecified {
281-
return nil, errors.Errorf("To avoid a redirect loop, you must modify at least one of the following components: protocol, port, hostname or path.")
282269
}
283270

284271
var query *string

pkg/gateway/routeutils/route_rule_action_test.go

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -66,59 +66,7 @@ func Test_buildHttpRedirectAction(t *testing.T) {
6666
wantErr: false,
6767
},
6868
{
69-
name: "redirect with prefix match only - uses literal prefix",
70-
filter: &gwv1.HTTPRequestRedirectFilter{
71-
Path: &gwv1.HTTPPathModifier{
72-
Type: gwv1.PrefixMatchHTTPPathModifier,
73-
ReplacePrefixMatch: &replacePrefixPath,
74-
},
75-
},
76-
want: &elbv2model.Action{
77-
Type: elbv2model.ActionTypeRedirect,
78-
RedirectConfig: &elbv2model.RedirectActionConfig{
79-
Path: &replacePrefixPath,
80-
},
81-
},
82-
wantErr: false,
83-
},
84-
{
85-
name: "redirect with prefix match and scheme - uses #{path}",
86-
filter: &gwv1.HTTPRequestRedirectFilter{
87-
Scheme: &scheme,
88-
Path: &gwv1.HTTPPathModifier{
89-
Type: gwv1.PrefixMatchHTTPPathModifier,
90-
ReplacePrefixMatch: &replacePrefixPath,
91-
},
92-
},
93-
want: &elbv2model.Action{
94-
Type: elbv2model.ActionTypeRedirect,
95-
RedirectConfig: &elbv2model.RedirectActionConfig{
96-
Path: awssdk.String("/#{path}"),
97-
Protocol: &expectedScheme,
98-
},
99-
},
100-
wantErr: false,
101-
},
102-
{
103-
name: "redirect with prefix match and port - uses #{path}",
104-
filter: &gwv1.HTTPRequestRedirectFilter{
105-
Port: (*gwv1.PortNumber)(&port),
106-
Path: &gwv1.HTTPPathModifier{
107-
Type: gwv1.PrefixMatchHTTPPathModifier,
108-
ReplacePrefixMatch: &replacePrefixPath,
109-
},
110-
},
111-
want: &elbv2model.Action{
112-
Type: elbv2model.ActionTypeRedirect,
113-
RedirectConfig: &elbv2model.RedirectActionConfig{
114-
Path: awssdk.String("/#{path}"),
115-
Port: &portString,
116-
},
117-
},
118-
wantErr: false,
119-
},
120-
{
121-
name: "redirect with prefix match and hostname - uses #{path}",
69+
name: "redirect with prefix - no path in redirect config",
12270
filter: &gwv1.HTTPRequestRedirectFilter{
12371
Hostname: (*gwv1.PreciseHostname)(&hostname),
12472
Path: &gwv1.HTTPPathModifier{
@@ -129,18 +77,11 @@ func Test_buildHttpRedirectAction(t *testing.T) {
12977
want: &elbv2model.Action{
13078
Type: elbv2model.ActionTypeRedirect,
13179
RedirectConfig: &elbv2model.RedirectActionConfig{
132-
Path: awssdk.String("/#{path}"),
13380
Host: &hostname,
13481
},
13582
},
13683
wantErr: false,
13784
},
138-
{
139-
name: "redirect with no component provided",
140-
filter: &gwv1.HTTPRequestRedirectFilter{},
141-
want: nil,
142-
wantErr: true,
143-
},
14485
{
14586
name: "invalid scheme provided",
14687
filter: &gwv1.HTTPRequestRedirectFilter{

0 commit comments

Comments
 (0)