diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go index 501355492..24466e4fc 100644 --- a/internal/ingress/controller/template/template.go +++ b/internal/ingress/controller/template/template.go @@ -120,6 +120,7 @@ var ( } return true }, + "escapeLiteralDollar": escapeLiteralDollar, "shouldConfigureLuaRestyWAF": shouldConfigureLuaRestyWAF, "buildLuaSharedDictionaries": buildLuaSharedDictionaries, "buildLocation": buildLocation, @@ -161,6 +162,20 @@ var ( } ) +// escapeLiteralDollar will replace the $ character with ${literal_dollar} +// which is made to work via the following configuration in the http section of +// the template: +// geo $literal_dollar { +// default "$"; +// } +func escapeLiteralDollar(input interface{}) string { + inputStr, ok := input.(string) + if !ok { + return "" + } + return strings.Replace(inputStr, `$`, `${literal_dollar}`, -1) +} + // formatIP will wrap IPv6 addresses in [] and return IPv4 addresses // without modification. If the input cannot be parsed as an IP address // it is returned without modification. diff --git a/internal/ingress/controller/template/template_test.go b/internal/ingress/controller/template/template_test.go index 5de8657d1..7fcd43d41 100644 --- a/internal/ingress/controller/template/template_test.go +++ b/internal/ingress/controller/template/template_test.go @@ -858,3 +858,29 @@ func TestBuildUpstreamName(t *testing.T) { } } } + +func TestEscapeLiteralDollar(t *testing.T) { + escapedPath := escapeLiteralDollar("/$") + expected := "/${literal_dollar}" + if escapedPath != expected { + t.Errorf("Expected %v but returned %v", expected, escapedPath) + } + + escapedPath = escapeLiteralDollar("/hello-$/world-$/") + expected = "/hello-${literal_dollar}/world-${literal_dollar}/" + if escapedPath != expected { + t.Errorf("Expected %v but returned %v", expected, escapedPath) + } + + leaveUnchagned := "/leave-me/unchagned" + escapedPath = escapeLiteralDollar(leaveUnchagned) + if escapedPath != leaveUnchagned { + t.Errorf("Expected %v but returned %v", leaveUnchagned, escapedPath) + } + + escapedPath = escapeLiteralDollar(false) + expected = "" + if escapedPath != expected { + t.Errorf("Expected %v but returned %v", expected, escapedPath) + } +} diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 282af4f1b..b86e6c904 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -347,6 +347,12 @@ http { } {{ end }} + # Create a variable that contains the literal $ character. + # This works because the geo module will not resolve variables. + geo $literal_dollar { + default "$"; + } + server_name_in_redirect off; port_in_redirect off; @@ -913,7 +919,7 @@ stream { set $ingress_name "{{ $ing.Rule }}"; set $service_name "{{ $ing.Service }}"; set $service_port "{{ $location.Port }}"; - set $location_path "{{ $location.Path }}"; + set $location_path "{{ $location.Path | escapeLiteralDollar }}"; {{ if $all.Cfg.EnableOpentracing }} opentracing_propagate_context;