safeweb: add support for "/" and "/foo" handler distinction (#13980)

By counting "/" elements in the pattern we catch many scenarios, but not
the root-level handler. If either of the patterns is "/", compare the
pattern length to pick the right one.

Updates https://github.com/tailscale/corp/issues/8027

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
operator_direct_connections
Andrew Lytvynov 3 weeks ago committed by GitHub
parent 3f626c0d77
commit 3477bfd234
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -225,12 +225,27 @@ const (
browserHandler browserHandler
) )
func (h handlerType) String() string {
switch h {
case browserHandler:
return "browser"
case apiHandler:
return "api"
default:
return "unknown"
}
}
// checkHandlerType returns either apiHandler or browserHandler, depending on // checkHandlerType returns either apiHandler or browserHandler, depending on
// whether apiPattern or browserPattern is more specific (i.e. which pattern // whether apiPattern or browserPattern is more specific (i.e. which pattern
// contains more pathname components). If they are equally specific, it returns // contains more pathname components). If they are equally specific, it returns
// unknownHandler. // unknownHandler.
func checkHandlerType(apiPattern, browserPattern string) handlerType { func checkHandlerType(apiPattern, browserPattern string) handlerType {
c := cmp.Compare(strings.Count(path.Clean(apiPattern), "/"), strings.Count(path.Clean(browserPattern), "/")) apiPattern, browserPattern = path.Clean(apiPattern), path.Clean(browserPattern)
c := cmp.Compare(strings.Count(apiPattern, "/"), strings.Count(browserPattern, "/"))
if apiPattern == "/" || browserPattern == "/" {
c = cmp.Compare(len(apiPattern), len(browserPattern))
}
switch { switch {
case c > 0: case c > 0:
return apiHandler return apiHandler

@ -527,13 +527,13 @@ func TestGetMoreSpecificPattern(t *testing.T) {
{ {
desc: "same prefix", desc: "same prefix",
a: "/foo/bar/quux", a: "/foo/bar/quux",
b: "/foo/bar/", b: "/foo/bar/", // path.Clean will strip the trailing slash.
want: apiHandler, want: apiHandler,
}, },
{ {
desc: "almost same prefix, but not a path component", desc: "almost same prefix, but not a path component",
a: "/goat/sheep/cheese", a: "/goat/sheep/cheese",
b: "/goat/sheepcheese/", b: "/goat/sheepcheese/", // path.Clean will strip the trailing slash.
want: apiHandler, want: apiHandler,
}, },
{ {
@ -554,6 +554,12 @@ func TestGetMoreSpecificPattern(t *testing.T) {
b: "///////", b: "///////",
want: unknownHandler, want: unknownHandler,
}, },
{
desc: "root-level",
a: "/latest",
b: "/", // path.Clean will NOT strip the trailing slash.
want: apiHandler,
},
} { } {
t.Run(tt.desc, func(t *testing.T) { t.Run(tt.desc, func(t *testing.T) {
got := checkHandlerType(tt.a, tt.b) got := checkHandlerType(tt.a, tt.b)

Loading…
Cancel
Save