Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 45 additions & 22 deletions internal/controller/nginx/config/servers.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ func initializeExternalLocations(
}
if !exactPathExists {
externalLocExact := http.Location{
Path: exactPath(externalLocPath),
Path: exactPath(rule.Path),
Type: locType,
}
extLocations = append(extLocations, externalLocExact)
Expand Down Expand Up @@ -458,23 +458,22 @@ func updateLocation(
mirrorPercentage *float64,
) http.Location {
filters := matchRule.Filters
path := pathRule.Path
grpc := pathRule.GRPC

if filters.InvalidFilter != nil {
location.Return = &http.Return{Code: http.StatusInternalServerError}
return location
}

location = updateLocationMirrorRoute(location, path, grpc)
location = updateLocationMirrorRoute(location, pathRule.Path, grpc)
location.Includes = append(location.Includes, createIncludesFromLocationSnippetsFilters(filters.SnippetsFilters)...)

if filters.RequestRedirect != nil {
return updateLocationRedirectFilter(location, filters.RequestRedirect, listenerPort, path)
return updateLocationRedirectFilter(location, filters.RequestRedirect, listenerPort, pathRule)
}

location = updateLocationRewriteFilter(location, filters.RequestURLRewrite, path)
location = updateLocationMirrorFilters(location, filters.RequestMirrors, path, mirrorPercentage)
location = updateLocationRewriteFilter(location, filters.RequestURLRewrite, pathRule)
location = updateLocationMirrorFilters(location, filters.RequestMirrors, pathRule.Path, mirrorPercentage)
location = updateLocationProxySettings(location, matchRule, grpc, keepAliveCheck)

return location
Expand All @@ -495,9 +494,9 @@ func updateLocationRedirectFilter(
location http.Location,
redirectFilter *dataplane.HTTPRequestRedirectFilter,
listenerPort int32,
path string,
pathRule dataplane.PathRule,
) http.Location {
ret, rewrite := createReturnAndRewriteConfigForRedirectFilter(redirectFilter, listenerPort, path)
ret, rewrite := createReturnAndRewriteConfigForRedirectFilter(redirectFilter, listenerPort, pathRule)
if rewrite.MainRewrite != "" {
location.Rewrites = append(location.Rewrites, rewrite.MainRewrite)
}
Expand All @@ -509,9 +508,9 @@ func updateLocationRedirectFilter(
func updateLocationRewriteFilter(
location http.Location,
rewriteFilter *dataplane.HTTPURLRewriteFilter,
path string,
pathRule dataplane.PathRule,
) http.Location {
rewrites := createRewritesValForRewriteFilter(rewriteFilter, path)
rewrites := createRewritesValForRewriteFilter(rewriteFilter, pathRule)
if rewrites != nil {
if location.Type == http.InternalLocationType && rewrites.InternalRewrite != "" {
location.Rewrites = append(location.Rewrites, rewrites.InternalRewrite)
Expand Down Expand Up @@ -658,7 +657,7 @@ func createProxySSLVerify(v *dataplane.VerifyTLS) *http.ProxySSLVerify {
func createReturnAndRewriteConfigForRedirectFilter(
filter *dataplane.HTTPRequestRedirectFilter,
listenerPort int32,
path string,
pathRule dataplane.PathRule,
) (*http.Return, *rewriteConfig) {
if filter == nil {
return nil, nil
Expand Down Expand Up @@ -702,7 +701,12 @@ func createReturnAndRewriteConfigForRedirectFilter(

rewrites := &rewriteConfig{}
if filter.Path != nil {
rewrites.MainRewrite = createMainRewriteForFilters(filter.Path, path)
mainRewrite := createMainRewriteForFilters(filter.Path, pathRule)
if mainRewrite == "" {
// Invalid configuration for the rewrite filter
return nil, nil
}
rewrites.MainRewrite = mainRewrite
body = fmt.Sprintf("%s://%s$uri$is_args$args", scheme, hostnamePort)
}

Expand All @@ -712,19 +716,26 @@ func createReturnAndRewriteConfigForRedirectFilter(
}, rewrites
}

func createMainRewriteForFilters(pathModifier *dataplane.HTTPPathModifier, path string) string {
func createMainRewriteForFilters(pathModifier *dataplane.HTTPPathModifier, pathRule dataplane.PathRule) string {
var mainRewrite string
switch pathModifier.Type {
case dataplane.ReplaceFullPath:
mainRewrite = fmt.Sprintf("^ %s", pathModifier.Replacement)
case dataplane.ReplacePrefixMatch:
// ReplacePrefixMatch is only compatible with a PathPrefix HTTPRouteMatch.
// ReplaceFullPath is compatible with PathTypeExact/PathTypePrefix/PathTypeRegularExpression HTTPRouteMatch.
// see https://gateway-api.sigs.k8s.io/reference/spec/?h=replaceprefixmatch#httppathmodifier
if pathRule.PathType != dataplane.PathTypePrefix {
return ""
}

filterPrefix := pathModifier.Replacement
if filterPrefix == "" {
filterPrefix = "/"
}

// capture everything following the configured prefix up to the first ?, if present.
regex := fmt.Sprintf("^%s([^?]*)?", path)
regex := fmt.Sprintf("^%s([^?]*)?", pathRule.Path)
// replace the configured prefix with the filter prefix, append the captured segment,
// and include the request arguments stored in nginx variable $args.
// https://nginx.org/en/docs/http/ngx_http_core_module.html#var_args
Expand All @@ -733,13 +744,13 @@ func createMainRewriteForFilters(pathModifier *dataplane.HTTPPathModifier, path
// if configured prefix does not end in /, but replacement prefix does end in /,
// then make sure that we *require* but *don't capture* a trailing slash in the request,
// otherwise we'll get duplicate slashes in the full replacement
if strings.HasSuffix(filterPrefix, "/") && !strings.HasSuffix(path, "/") {
regex = fmt.Sprintf("^%s(?:/([^?]*))?", path)
if strings.HasSuffix(filterPrefix, "/") && !strings.HasSuffix(pathRule.Path, "/") {
regex = fmt.Sprintf("^%s(?:/([^?]*))?", pathRule.Path)
}

// if configured prefix ends in / we won't capture it for a request (since it's not in the regex),
// so append it to the replacement prefix if the replacement prefix doesn't already end in /
if strings.HasSuffix(path, "/") && !strings.HasSuffix(filterPrefix, "/") {
if strings.HasSuffix(pathRule.Path, "/") && !strings.HasSuffix(filterPrefix, "/") {
replacement = fmt.Sprintf("%s/$1?$args?", filterPrefix)
}

Expand All @@ -749,7 +760,10 @@ func createMainRewriteForFilters(pathModifier *dataplane.HTTPPathModifier, path
return mainRewrite
}

func createRewritesValForRewriteFilter(filter *dataplane.HTTPURLRewriteFilter, path string) *rewriteConfig {
func createRewritesValForRewriteFilter(
filter *dataplane.HTTPURLRewriteFilter,
pathRule dataplane.PathRule,
) *rewriteConfig {
if filter == nil {
return nil
}
Expand All @@ -758,8 +772,13 @@ func createRewritesValForRewriteFilter(filter *dataplane.HTTPURLRewriteFilter, p
if filter.Path != nil {
rewrites.InternalRewrite = "^ $request_uri"

// for URLRewriteFilter, we add a break to the rewrite to prevent further processing of the request.
rewrites.MainRewrite = fmt.Sprintf("%s break", createMainRewriteForFilters(filter.Path, path))
mainRewrite := createMainRewriteForFilters(filter.Path, pathRule)
if mainRewrite == "" {
// Invalid configuration for the rewrite filter
return nil
}
// For URLRewriteFilter, add "break" to prevent further processing of the request.
rewrites.MainRewrite = fmt.Sprintf("%s break", mainRewrite)
}

return rewrites
Expand Down Expand Up @@ -982,14 +1001,18 @@ func createPath(rule dataplane.PathRule) string {
switch rule.PathType {
case dataplane.PathTypeExact:
return exactPath(rule.Path)
case dataplane.PathTypePrefix:
return fmt.Sprintf("^~ %s", rule.Path)
case dataplane.PathTypeRegularExpression:
return fmt.Sprintf("~ %s", rule.Path)
default:
return rule.Path
return "" // should never happen because path type is validated earlier
Copy link
Contributor

Choose a reason for hiding this comment

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

should we panic here like we do for other cases @ciarams87 ?

Copy link
Contributor

Choose a reason for hiding this comment

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

i guess its fine, this is how we have handled it in the past so should be good

Copy link
Contributor

Choose a reason for hiding this comment

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

I think your first instinct was correct actually - this should be a panic. Now this function silently returns an invalid location path instead of at least returning the original path as a fallback. This is a programmer error (all path types should be handled), not a runtime error from user input (which is validated earlier), so panic() is appropriate and consistent.

}
}

func createDefaultRootLocation() http.Location {
return http.Location{
Path: "/",
Path: "= /",
Return: &http.Return{Code: http.StatusNotFound},
}
}
Expand Down
Loading
Loading