From c6dec305357868ec9ba7fbc45e6cb70404cc23a6 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Mon, 23 Nov 2020 14:51:35 -0500 Subject: [PATCH] caddyfile: Add support for env var defaults; add tests (#3682) * caddyfile: Add support for env var defaults, tests * caddyfile: Use ?? instead, fix redundant cast, remove env chaining * caddyfile: Use : instead --- caddyconfig/caddyfile/parse.go | 25 +++++++++++++++++++------ caddyconfig/caddyfile/parse_test.go | 17 +++++++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/caddyconfig/caddyfile/parse.go b/caddyconfig/caddyfile/parse.go index 4ae98ca4..50e3244b 100755 --- a/caddyconfig/caddyfile/parse.go +++ b/caddyconfig/caddyfile/parse.go @@ -60,21 +60,31 @@ func replaceEnvVars(input []byte) ([]byte, error) { end += begin + len(spanOpen) // make end relative to input, not begin // get the name; if there is no name, skip it - envVarName := input[begin+len(spanOpen) : end] - if len(envVarName) == 0 { + envString := input[begin+len(spanOpen) : end] + if len(envString) == 0 { offset = end + len(spanClose) continue } + // split the string into a key and an optional default + envParts := strings.SplitN(string(envString), envVarDefaultDelimiter, 2) + + // do a lookup for the env var, replace with the default if not found + envVarValue, found := os.LookupEnv(envParts[0]) + if !found && len(envParts) == 2 { + envVarValue = envParts[1] + } + // get the value of the environment variable - envVarValue := []byte(os.ExpandEnv(os.Getenv(string(envVarName)))) + // note that this causes one-level deep chaining + envVarBytes := []byte(envVarValue) // splice in the value input = append(input[:begin], - append(envVarValue, input[end+len(spanClose):]...)...) + append(envVarBytes, input[end+len(spanClose):]...)...) // continue at the end of the replacement - offset = begin + len(envVarValue) + offset = begin + len(envVarBytes) } return input, nil } @@ -548,4 +558,7 @@ func (s Segment) Directive() string { // spanOpen and spanClose are used to bound spans that // contain the name of an environment variable. -var spanOpen, spanClose = []byte{'{', '$'}, []byte{'}'} +var ( + spanOpen, spanClose = []byte{'{', '$'}, []byte{'}'} + envVarDefaultDelimiter = ":" +) diff --git a/caddyconfig/caddyfile/parse_test.go b/caddyconfig/caddyfile/parse_test.go index 12c30c86..94a69a41 100755 --- a/caddyconfig/caddyfile/parse_test.go +++ b/caddyconfig/caddyfile/parse_test.go @@ -478,6 +478,7 @@ func TestParseAll(t *testing.T) { func TestEnvironmentReplacement(t *testing.T) { os.Setenv("FOOBAR", "foobar") + os.Setenv("CHAINED", "$FOOBAR") for i, test := range []struct { input string @@ -523,6 +524,22 @@ func TestEnvironmentReplacement(t *testing.T) { input: "{$FOOBAR}{$FOOBAR}", expect: "foobarfoobar", }, + { + input: "{$CHAINED}", + expect: "$FOOBAR", // should not chain env expands + }, + { + input: "{$FOO:default}", + expect: "default", + }, + { + input: "foo{$BAR:bar}baz", + expect: "foobarbaz", + }, + { + input: "foo{$BAR:$FOOBAR}baz", + expect: "foo$FOOBARbaz", // should not chain env expands + }, { input: "{$FOOBAR", expect: "{$FOOBAR",