Skip to content

Conversation

@zac-nixon
Copy link
Collaborator

Description

Supports path and host header rewrites using URLRewrite found in HTTPRouteRule. https://gateway-api.sigs.k8s.io/guides/http-redirect-rewrite/#rewrites

I put lots of descriptions in the code. The TL;DR is that we can fully support both path and header based rewrites using the newly launched ALB URLRewrite feature. One piece that still needs figuring out is that ALB has more powerful rewrite capabilities than listed here. Originally, I was going to use the ListenerRuleConfiguration object to specify it. However, to keep this change manageable, I have only implemented the Gateway API spec.

Checklist

  • Added tests that cover your change (if possible)
  • Added/modified documentation as required (such as the README.md, or the docs directory)
  • Manually tested
  • Made sure the title of the PR is a good description that can go into the release notes

BONUS POINTS checklist: complete for good vibes and maybe prizes?! 🤯

  • Backfilled missing tests for code in same general area 🎉
  • Refactored something and made the world a better place 🌟

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Oct 28, 2025
@k8s-ci-robot k8s-ci-robot requested a review from M00nF1sh October 28, 2025 21:06
@k8s-ci-robot k8s-ci-robot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Oct 28, 2025
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: zac-nixon

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Oct 28, 2025
match := *httpMatch.Path.Value

/*
If we're being asked to replace a prefix with "", we still need to keep one '/' to form a valid path.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Great job on explaining this in details.
We should also add good documentation with these samples in our docs for this feature once we implement it with ELB gaps.

},
Filters: []gwv1.HTTPRouteFilter{
{
URLRewrite: &gwv1.HTTPURLRewriteFilter{
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would have preferred if the spec added this validations instead of us doing this for our implementation. Any reason that spec is not doing this on their side?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Turns out route validator is not needed -

# httproutes.gateway.networking.k8s.io "http-app-1" was not valid:
# * spec.rules[0]: Invalid value: "object": When using URLRewrite filter with path.replacePrefixMatch, exactly one PathPrefix match must be specified

@shraddhabang
Copy link
Collaborator

Can you also add E2E tests for this?

case HTTPRouteKind:
return buildHTTPRuleTransforms(gwRule.CommonRulePrecedence.Rule.GetRawRouteRule().(*gwv1.HTTPRouteRule), gwRule.HTTPMatch)
default:
return []elbv2model.Transform{}
Copy link
Collaborator

Choose a reason for hiding this comment

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

for any other cases, do we want to add a v(1) logging or warning saying only httpRoute is supported for transform?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think so. This is already documented within the gateway api

return transforms
}

func generateHostHeaderRewriteTransform(hostname gwv1.PreciseHostname) elbv2model.Transform {
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe rename it to generateHttpHostHeaderRewriteTransform, same for generateURLRewritePathTransform

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

any explanation here? :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

because it feels like this function is only for HTTPRoute, but it is a nit change

}

func generatePrefixReplacementRegex(httpMatch *gwv1.HTTPRouteMatch, replacement string) (string, string) {
match := *httpMatch.Path.Value
Copy link
Collaborator

Choose a reason for hiding this comment

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

i did not see where we are checking nil for httpMatch

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it's done in the routeValidator

input path = '/foo/', prefixRegex = '(^/foo(/)?)', replacement value = '/cat/$2' results in (again) '/cat//'
Without the capture group, we would have one '/' too few.
input path = '/foo/bar', prefixRegex = '(^/foo(/)?)', replacement value = '/cat$2' results in '/catbar'
Copy link
Collaborator

Choose a reason for hiding this comment

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

thanks for all explanation. can you verify if *httpMatch.Path.Value(match) can be something like /foo/ or replacement can be with Trailing Slash? those cases will lead to double slash right?

Copy link
Collaborator Author

@zac-nixon zac-nixon Oct 30, 2025

Choose a reason for hiding this comment

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

Yup it can, I actually have an explicit test case for this, name = prefix path rewrite with explicit '/' on suffix. To answer your question, no we won't add a double slash, because we check if the replacement ends with a /, in that case we don't append the optional capture group.


// 2. Remove routes that aren't granted attachment by the listener.
// 3. Validate route configuration, filter out bad configurations.
validatedRoutes, validationErrors := l.routeValidator.filterToValidRoutes(gw, foo)
Copy link
Collaborator

Choose a reason for hiding this comment

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

can you attach a screenshot of this status update in route to show a failed case with correct failed reason?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Turns out route validator is not needed -

# httproutes.gateway.networking.k8s.io "http-app-1" was not valid:
# * spec.rules[0]: Invalid value: "object": When using URLRewrite filter with path.replacePrefixMatch, exactly one PathPrefix match must be specified

@zac-nixon
Copy link
Collaborator Author

E2E test result -

Ran 2 of 18 Specs in 915.365 seconds
SUCCESS! -- 2 Passed | 0 Failed | 0 Pending | 16 Skipped
PASS

@k8s-ci-robot k8s-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Oct 30, 2025
},
})
Expect(err).NotTo(HaveOccurred())
})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we verify the transform are applied in the response by sending the http request?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We don't do this for other listener rules, I don't see a reason to do it here.

@zac-nixon zac-nixon force-pushed the znixon/gw-api-transforms-ga-version branch from 4439c4a to 3a3e396 Compare October 30, 2025 18:40
@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 31, 2025
@zac-nixon zac-nixon force-pushed the znixon/gw-api-transforms-ga-version branch from 3a3e396 to fb3074e Compare October 31, 2025 21:23
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants