From df76cc33a5fa7474814611ae974119150180cab0 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Fri, 15 Sep 2017 20:56:04 +0200 Subject: [PATCH] Fixes entry points configuration. --- configuration/configuration.go | 57 ++++---- configuration/configuration_test.go | 201 ++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+), 25 deletions(-) create mode 100644 configuration/configuration_test.go diff --git a/configuration/configuration.go b/configuration/configuration.go index a8494436a..2a21ab398 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -193,18 +193,11 @@ func (ep *EntryPoints) String() string { // Set's argument is a string to be parsed to set the flag. // It's a comma-separated list, so we split it. func (ep *EntryPoints) Set(value string) error { - regex := regexp.MustCompile(`(?:Name:(?P\S*))\s*(?:Address:(?P
\S*))?\s*(?:TLS:(?P\S*))?\s*((?PTLS))?\s*(?:CA:(?P\S*))?\s*(?:Redirect.EntryPoint:(?P\S*))?\s*(?:Redirect.Regex:(?P\\S*))?\s*(?:Redirect.Replacement:(?P\S*))?\s*(?:Compress:(?P\S*))?\s*(?:WhiteListSourceRange:(?P\S*))?\s*(?:ProxyProtocol:(?P\S*))?`) - match := regex.FindAllStringSubmatch(value, -1) - if match == nil { - return fmt.Errorf("bad EntryPoints format: %s", value) - } - matchResult := match[0] - result := make(map[string]string) - for i, name := range regex.SubexpNames() { - if i != 0 { - result[name] = matchResult[i] - } + result, err := parseEntryPointsConfiguration(value) + if err != nil { + return err } + var configTLS *TLS if len(result["TLS"]) > 0 { certs := Certificates{} @@ -232,24 +225,13 @@ func (ep *EntryPoints) Set(value string) error { } } - compress := false - if len(result["Compress"]) > 0 { - compress = strings.EqualFold(result["Compress"], "true") || - strings.EqualFold(result["Compress"], "enable") || - strings.EqualFold(result["Compress"], "on") - } - whiteListSourceRange := []string{} if len(result["WhiteListSourceRange"]) > 0 { whiteListSourceRange = strings.Split(result["WhiteListSourceRange"], ",") } - proxyprotocol := false - if len(result["ProxyProtocol"]) > 0 { - proxyprotocol = strings.EqualFold(result["ProxyProtocol"], "true") || - strings.EqualFold(result["ProxyProtocol"], "enable") || - strings.EqualFold(result["ProxyProtocol"], "on") - } + compress := toBool(result, "Compress") + proxyProtocol := toBool(result, "ProxyProtocol") (*ep)[result["Name"]] = &EntryPoint{ Address: result["Address"], @@ -257,12 +239,37 @@ func (ep *EntryPoints) Set(value string) error { Redirect: redirect, Compress: compress, WhitelistSourceRange: whiteListSourceRange, - ProxyProtocol: proxyprotocol, + ProxyProtocol: proxyProtocol, } return nil } +func parseEntryPointsConfiguration(value string) (map[string]string, error) { + regex := regexp.MustCompile(`(?:Name:(?P\S*))\s*(?:Address:(?P
\S*))?\s*(?:TLS:(?P\S*))?\s*(?PTLS)?\s*(?:CA:(?P\S*))?\s*(?:Redirect\.EntryPoint:(?P\S*))?\s*(?:Redirect\.Regex:(?P\S*))?\s*(?:Redirect\.Replacement:(?P\S*))?\s*(?:Compress:(?P\S*))?\s*(?:WhiteListSourceRange:(?P\S*))?\s*(?:ProxyProtocol:(?P\S*))?`) + match := regex.FindAllStringSubmatch(value, -1) + if match == nil { + return nil, fmt.Errorf("bad EntryPoints format: %s", value) + } + matchResult := match[0] + result := make(map[string]string) + for i, name := range regex.SubexpNames() { + if i != 0 && len(matchResult[i]) != 0 { + result[name] = matchResult[i] + } + } + return result, nil +} + +func toBool(conf map[string]string, key string) bool { + if val, ok := conf[key]; ok { + return strings.EqualFold(val, "true") || + strings.EqualFold(val, "enable") || + strings.EqualFold(val, "on") + } + return false +} + // Get return the EntryPoints map func (ep *EntryPoints) Get() interface{} { return EntryPoints(*ep) diff --git a/configuration/configuration_test.go b/configuration/configuration_test.go new file mode 100644 index 000000000..5d476e4df --- /dev/null +++ b/configuration/configuration_test.go @@ -0,0 +1,201 @@ +package configuration + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_parseEntryPointsConfiguration(t *testing.T) { + testCases := []struct { + name string + value string + expectedResult map[string]string + }{ + { + name: "all parameters", + value: "Name:foo Address:bar TLS:goo TLS CA:car Redirect.EntryPoint:RedirectEntryPoint Redirect.Regex:RedirectRegex Redirect.Replacement:RedirectReplacement Compress:true WhiteListSourceRange:WhiteListSourceRange ProxyProtocol:true", + expectedResult: map[string]string{ + "Name": "foo", + "Address": "bar", + "CA": "car", + "TLS": "goo", + "TLSACME": "TLS", + "RedirectEntryPoint": "RedirectEntryPoint", + "RedirectRegex": "RedirectRegex", + "RedirectReplacement": "RedirectReplacement", + "WhiteListSourceRange": "WhiteListSourceRange", + "ProxyProtocol": "true", + "Compress": "true", + }, + }, + { + name: "proxy protocol on", + value: "Name:foo ProxyProtocol:on", + expectedResult: map[string]string{ + "Name": "foo", + "ProxyProtocol": "on", + }, + }, + { + name: "compress on", + value: "Name:foo Compress:on", + expectedResult: map[string]string{ + "Name": "foo", + "Compress": "on", + }, + }, + { + name: "TLS", + value: "Name:foo TLS:goo TLS", + expectedResult: map[string]string{ + "Name": "foo", + "TLS": "goo", + "TLSACME": "TLS", + }, + }, + } + + for _, test := range testCases { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + conf, err := parseEntryPointsConfiguration(test.value) + if err != nil { + t.Error(err) + } + + for key, value := range conf { + fmt.Println(key, value) + } + + assert.Len(t, conf, len(test.expectedResult)) + assert.Equal(t, test.expectedResult, conf) + }) + } +} + +func Test_toBool(t *testing.T) { + testCases := []struct { + name string + value string + key string + expectedBool bool + }{ + { + name: "on", + value: "on", + key: "foo", + expectedBool: true, + }, + { + name: "true", + value: "true", + key: "foo", + expectedBool: true, + }, + { + name: "enable", + value: "enable", + key: "foo", + expectedBool: true, + }, + { + name: "arbitrary string", + value: "bar", + key: "foo", + expectedBool: false, + }, + { + name: "no existing entry", + value: "bar", + key: "fii", + expectedBool: false, + }, + } + + for _, test := range testCases { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + conf := map[string]string{ + "foo": test.value, + } + + result := toBool(conf, test.key) + + assert.Equal(t, test.expectedBool, result) + }) + } +} + +func TestEntryPoints_Set(t *testing.T) { + testCases := []struct { + name string + expression string + expectedEntryPointName string + expectedEntryPoint *EntryPoint + }{ + { + name: "all parameters", + expression: "Name:foo Address:bar TLS:goo,gii TLS CA:car Redirect.EntryPoint:RedirectEntryPoint Redirect.Regex:RedirectRegex Redirect.Replacement:RedirectReplacement Compress:true WhiteListSourceRange:Range ProxyProtocol:true", + expectedEntryPointName: "foo", + expectedEntryPoint: &EntryPoint{ + Address: "bar", + Redirect: &Redirect{ + EntryPoint: "RedirectEntryPoint", + Regex: "RedirectRegex", + Replacement: "RedirectReplacement", + }, + Compress: true, + ProxyProtocol: true, + WhitelistSourceRange: []string{"Range"}, + TLS: &TLS{ + ClientCAFiles: []string{"car"}, + Certificates: Certificates{ + { + CertFile: FileOrContent("goo"), + KeyFile: FileOrContent("gii"), + }, + }, + }, + }, + }, + { + name: "compress on", + expression: "Name:foo Compress:on", + expectedEntryPointName: "foo", + expectedEntryPoint: &EntryPoint{ + Compress: true, + WhitelistSourceRange: []string{}, + }, + }, + { + name: "compress true", + expression: "Name:foo Compress:true", + expectedEntryPointName: "foo", + expectedEntryPoint: &EntryPoint{ + Compress: true, + WhitelistSourceRange: []string{}, + }, + }, + } + + for _, test := range testCases { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + eps := EntryPoints{} + err := eps.Set(test.expression) + require.NoError(t, err) + + ep := eps[test.expectedEntryPointName] + assert.EqualValues(t, test.expectedEntryPoint, ep) + }) + } +}