diff --git a/webserver/webserver.go b/webserver/webserver.go index c30fcda..b0de1e1 100644 --- a/webserver/webserver.go +++ b/webserver/webserver.go @@ -242,20 +242,23 @@ func serveFile(w http.ResponseWriter, r *http.Request, p string) { http.ServeContent(w, r, fi.Name(), fi.ModTime(), f) } -func parseGroupName(path string) string { - if !strings.HasPrefix(path, "/group/") { +func parseGroupName(prefix string, p string) string { + if !strings.HasPrefix(p, prefix) { return "" } - name := path[len("/group/"):] + name := p[len("/group/"):] if name == "" { return "" } - if name[len(name)-1] == '/' { - name = name[:len(name)-1] + if filepath.Separator != '/' && + strings.ContainsRune(name, filepath.Separator) { + return "" } - return name + + name = path.Clean("/" + name) + return name[1:] } func groupHandler(w http.ResponseWriter, r *http.Request) { @@ -264,14 +267,14 @@ func groupHandler(w http.ResponseWriter, r *http.Request) { } mungeHeader(w) - name := parseGroupName(r.URL.Path) + name := parseGroupName("/group/", r.URL.Path) if name == "" { notFound(w) return } - if strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(w, r, r.URL.Path[:len(r.URL.Path)-1], + if r.URL.Path != "/group/" + name { + http.Redirect(w, r, "/group/" + name, http.StatusPermanentRedirect) return } diff --git a/webserver/webserver_test.go b/webserver/webserver_test.go new file mode 100644 index 0000000..f7d36c2 --- /dev/null +++ b/webserver/webserver_test.go @@ -0,0 +1,31 @@ +package webserver + +import ( + "testing" +) + +func TestParseGroupName(t *testing.T) { + a := []struct{ p, g string }{ + {"", ""}, + {"/foo", ""}, + {"foo", ""}, + {"group/foo", ""}, + {"/group", ""}, + {"/group/..", ""}, + {"/group/foo/../bar", "bar"}, + {"/group/foo", "foo"}, + {"/group/foo/", "foo"}, + {"/group/foo/bar", "foo/bar"}, + {"/group/foo/bar/", "foo/bar"}, + } + + for _, pg := range a { + t.Run(pg.p, func(t *testing.T) { + g := parseGroupName("/group/", pg.p) + if g != pg.g { + t.Errorf("Path %v, got %v, expected %v", + pg.p, g, pg.g) + } + }) + } +}