From 9e1e189f47d468c8949ba99cd1169ab39b4c7d5d Mon Sep 17 00:00:00 2001 From: Eric Herbrandson Date: Wed, 19 Sep 2018 21:48:57 -0500 Subject: [PATCH 1/4] Added new case insensitive matcher --- config/load.go | 2 +- route/matcher.go | 6 ++++++ route/matcher_test.go | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/config/load.go b/config/load.go index 098d0c2c1..3261ccfd9 100644 --- a/config/load.go +++ b/config/load.go @@ -247,7 +247,7 @@ func load(cmdline, environ, envprefix []string, props *properties.Properties) (c return nil, fmt.Errorf("invalid proxy.strategy: %s", cfg.Proxy.Strategy) } - if cfg.Proxy.Matcher != "prefix" && cfg.Proxy.Matcher != "glob" { + if cfg.Proxy.Matcher != "prefix" && cfg.Proxy.Matcher != "glob" && cfg.Proxy.Matcher != "noCase" { return nil, fmt.Errorf("invalid proxy.matcher: %s", cfg.Proxy.Matcher) } diff --git a/route/matcher.go b/route/matcher.go index 3a7274c66..b0449ff0f 100644 --- a/route/matcher.go +++ b/route/matcher.go @@ -12,6 +12,7 @@ type matcher func(uri string, r *Route) bool var Matcher = map[string]matcher{ "prefix": prefixMatcher, "glob": globMatcher, + "noCase": noCaseMatcher, } // prefixMatcher matches path to the routes' path. @@ -23,3 +24,8 @@ func prefixMatcher(uri string, r *Route) bool { func globMatcher(uri string, r *Route) bool { return r.Glob.Match(uri) } + +// noCase matches path to the routes' path ignoring case +func noCaseMatcher(uri string, r *Route) bool { + return strings.EqualFold(uri, r.Path) +} diff --git a/route/matcher_test.go b/route/matcher_test.go index 59a068c90..2972acbbb 100644 --- a/route/matcher_test.go +++ b/route/matcher_test.go @@ -60,3 +60,24 @@ func TestGlobMatcher(t *testing.T) { }) } } + +func TestNoCaseMatcher(t *testing.T) { + tests := []struct { + uri string + matches bool + route *Route + }{ + {uri: "/fool", matches: false, route: &Route{Path: "/foo"}}, + {uri: "/foo", matches: true, route: &Route{Path: "/foo"}}, + {uri: "/Foo", matches: true, route: &Route{Path: "/foo"}}, + {uri: "/foo", matches: true, route: &Route{Path: "/Foo"}}, + } + + for _, tt := range tests { + t.Run(tt.uri, func(t *testing.T) { + if got, want := noCaseMatcher(tt.uri, tt.route), tt.matches; got != want { + t.Fatalf("got %v want %v", got, want) + } + }) + } +} From b77f9d9bca17d4f9e6d772eeb041b9743fa4d756 Mon Sep 17 00:00:00 2001 From: Eric Herbrandson Date: Thu, 20 Sep 2018 11:52:23 -0500 Subject: [PATCH 2/4] Updates per PR comments. Also, modified noCaseMatcher to be a prefix match --- config/load.go | 2 +- config/load_test.go | 7 +++++++ docs/content/ref/proxy.matcher.md | 6 ++++-- fabio.properties | 1 + route/matcher.go | 6 ++++-- route/matcher_test.go | 4 ++-- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/config/load.go b/config/load.go index 3261ccfd9..aa6cfda26 100644 --- a/config/load.go +++ b/config/load.go @@ -247,7 +247,7 @@ func load(cmdline, environ, envprefix []string, props *properties.Properties) (c return nil, fmt.Errorf("invalid proxy.strategy: %s", cfg.Proxy.Strategy) } - if cfg.Proxy.Matcher != "prefix" && cfg.Proxy.Matcher != "glob" && cfg.Proxy.Matcher != "noCase" { + if cfg.Proxy.Matcher != "prefix" && cfg.Proxy.Matcher != "glob" && cfg.Proxy.Matcher != "nocase" { return nil, fmt.Errorf("invalid proxy.matcher: %s", cfg.Proxy.Matcher) } diff --git a/config/load_test.go b/config/load_test.go index fc17f186d..8f3150548 100644 --- a/config/load_test.go +++ b/config/load_test.go @@ -306,6 +306,13 @@ func TestLoad(t *testing.T) { return cfg }, }, + { + args: []string{"-proxy.matcher", "nocase"}, + cfg: func(cfg *Config) *Config { + cfg.Proxy.Matcher = "nocase" + return cfg + }, + }, { args: []string{"-proxy.noroutestatus", "555"}, cfg: func(cfg *Config) *Config { diff --git a/docs/content/ref/proxy.matcher.md b/docs/content/ref/proxy.matcher.md index f029f29ef..38af329e7 100644 --- a/docs/content/ref/proxy.matcher.md +++ b/docs/content/ref/proxy.matcher.md @@ -8,8 +8,8 @@ title: "proxy.matcher" * `prefix`: prefix matching * `glob`: glob matching -When `prefix` matching is enabled then the route path must be a -prefix of the request URI, e.g. `/foo` matches `/foo`, `/foot` but +When `prefix` matching is enabled then the route path must be a +prefix of the request URI, e.g. `/foo` matches `/foo`, `/foot` but not `/fo`. When `glob` matching is enabled the route is evaluated according to @@ -19,6 +19,8 @@ function. For example, `/foo*` matches `/foo`, `/fool` and `/fools`. Also, `/foo/*/bar` matches `/foo/x/bar`. +`nocase` matching is similar to `prefix`, except it uses a case insensitive comparison + The default is proxy.matcher = prefix diff --git a/fabio.properties b/fabio.properties index 703027d3d..4887267d8 100644 --- a/fabio.properties +++ b/fabio.properties @@ -297,6 +297,7 @@ # # prefix: prefix matching # glob: glob matching +# nocase: matches using a case insensitive test # # The default is # diff --git a/route/matcher.go b/route/matcher.go index b0449ff0f..dd951ce49 100644 --- a/route/matcher.go +++ b/route/matcher.go @@ -12,7 +12,7 @@ type matcher func(uri string, r *Route) bool var Matcher = map[string]matcher{ "prefix": prefixMatcher, "glob": globMatcher, - "noCase": noCaseMatcher, + "nocase": noCaseMatcher, } // prefixMatcher matches path to the routes' path. @@ -27,5 +27,7 @@ func globMatcher(uri string, r *Route) bool { // noCase matches path to the routes' path ignoring case func noCaseMatcher(uri string, r *Route) bool { - return strings.EqualFold(uri, r.Path) + lowerURI := strings.ToLower(uri) + lowerPath := strings.ToLower(r.Path) + return strings.HasPrefix(lowerURI, lowerPath) } diff --git a/route/matcher_test.go b/route/matcher_test.go index 2972acbbb..89284bbd9 100644 --- a/route/matcher_test.go +++ b/route/matcher_test.go @@ -67,9 +67,9 @@ func TestNoCaseMatcher(t *testing.T) { matches bool route *Route }{ - {uri: "/fool", matches: false, route: &Route{Path: "/foo"}}, + {uri: "/foo", matches: false, route: &Route{Path: "/fool"}}, {uri: "/foo", matches: true, route: &Route{Path: "/foo"}}, - {uri: "/Foo", matches: true, route: &Route{Path: "/foo"}}, + {uri: "/Fool", matches: true, route: &Route{Path: "/foo"}}, {uri: "/foo", matches: true, route: &Route{Path: "/Foo"}}, } From 53b26b21bcff28e9a8ae4e40c8d7a7ebe5b934a1 Mon Sep 17 00:00:00 2001 From: Eric Herbrandson Date: Thu, 20 Sep 2018 14:06:00 -0500 Subject: [PATCH 3/4] Renaming 'nocase' to 'iprefix' --- config/load.go | 2 +- config/load_test.go | 4 ++-- docs/content/ref/proxy.matcher.md | 2 +- fabio.properties | 2 +- route/matcher.go | 10 +++++----- route/matcher_test.go | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/config/load.go b/config/load.go index aa6cfda26..72b2b70e4 100644 --- a/config/load.go +++ b/config/load.go @@ -247,7 +247,7 @@ func load(cmdline, environ, envprefix []string, props *properties.Properties) (c return nil, fmt.Errorf("invalid proxy.strategy: %s", cfg.Proxy.Strategy) } - if cfg.Proxy.Matcher != "prefix" && cfg.Proxy.Matcher != "glob" && cfg.Proxy.Matcher != "nocase" { + if cfg.Proxy.Matcher != "prefix" && cfg.Proxy.Matcher != "glob" && cfg.Proxy.Matcher != "iprefix" { return nil, fmt.Errorf("invalid proxy.matcher: %s", cfg.Proxy.Matcher) } diff --git a/config/load_test.go b/config/load_test.go index 8f3150548..29fb9682a 100644 --- a/config/load_test.go +++ b/config/load_test.go @@ -307,9 +307,9 @@ func TestLoad(t *testing.T) { }, }, { - args: []string{"-proxy.matcher", "nocase"}, + args: []string{"-proxy.matcher", "iprefix"}, cfg: func(cfg *Config) *Config { - cfg.Proxy.Matcher = "nocase" + cfg.Proxy.Matcher = "iprefix" return cfg }, }, diff --git a/docs/content/ref/proxy.matcher.md b/docs/content/ref/proxy.matcher.md index 38af329e7..dea344fef 100644 --- a/docs/content/ref/proxy.matcher.md +++ b/docs/content/ref/proxy.matcher.md @@ -19,7 +19,7 @@ function. For example, `/foo*` matches `/foo`, `/fool` and `/fools`. Also, `/foo/*/bar` matches `/foo/x/bar`. -`nocase` matching is similar to `prefix`, except it uses a case insensitive comparison +`iprefix` matching is similar to `prefix`, except it uses a case insensitive comparison The default is diff --git a/fabio.properties b/fabio.properties index 4887267d8..42177a9fc 100644 --- a/fabio.properties +++ b/fabio.properties @@ -297,7 +297,7 @@ # # prefix: prefix matching # glob: glob matching -# nocase: matches using a case insensitive test +# iprefix: case-insensitive prefix matching # # The default is # diff --git a/route/matcher.go b/route/matcher.go index dd951ce49..e1e817641 100644 --- a/route/matcher.go +++ b/route/matcher.go @@ -10,9 +10,9 @@ type matcher func(uri string, r *Route) bool // Matcher contains the available matcher functions. // Update config/load.go#load after updating. var Matcher = map[string]matcher{ - "prefix": prefixMatcher, - "glob": globMatcher, - "nocase": noCaseMatcher, + "prefix": prefixMatcher, + "glob": globMatcher, + "iprefix": iPrefixMatcher, } // prefixMatcher matches path to the routes' path. @@ -25,8 +25,8 @@ func globMatcher(uri string, r *Route) bool { return r.Glob.Match(uri) } -// noCase matches path to the routes' path ignoring case -func noCaseMatcher(uri string, r *Route) bool { +// iPrefixMatcher matches path to the routes' path ignoring case +func iPrefixMatcher(uri string, r *Route) bool { lowerURI := strings.ToLower(uri) lowerPath := strings.ToLower(r.Path) return strings.HasPrefix(lowerURI, lowerPath) diff --git a/route/matcher_test.go b/route/matcher_test.go index 89284bbd9..163be120d 100644 --- a/route/matcher_test.go +++ b/route/matcher_test.go @@ -61,7 +61,7 @@ func TestGlobMatcher(t *testing.T) { } } -func TestNoCaseMatcher(t *testing.T) { +func TestIPrefixMatcher(t *testing.T) { tests := []struct { uri string matches bool @@ -75,7 +75,7 @@ func TestNoCaseMatcher(t *testing.T) { for _, tt := range tests { t.Run(tt.uri, func(t *testing.T) { - if got, want := noCaseMatcher(tt.uri, tt.route), tt.matches; got != want { + if got, want := iPrefixMatcher(tt.uri, tt.route), tt.matches; got != want { t.Fatalf("got %v want %v", got, want) } }) From 972d8518e9bd83b0992d76f2d79c1c2583c06904 Mon Sep 17 00:00:00 2001 From: Eric Herbrandson Date: Thu, 20 Sep 2018 14:07:56 -0500 Subject: [PATCH 4/4] Leaving a comment in iPrefixMatcher per PR comments --- route/matcher.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/route/matcher.go b/route/matcher.go index e1e817641..4cdbbbbe2 100644 --- a/route/matcher.go +++ b/route/matcher.go @@ -27,6 +27,8 @@ func globMatcher(uri string, r *Route) bool { // iPrefixMatcher matches path to the routes' path ignoring case func iPrefixMatcher(uri string, r *Route) bool { + // todo(fs): if this turns out to be a performance issue we should cache + // todo(fs): strings.ToLower(r.Path) in r.PathLower lowerURI := strings.ToLower(uri) lowerPath := strings.ToLower(r.Path) return strings.HasPrefix(lowerURI, lowerPath)