diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/caddyhttp/fileserver/staticfiles.go | 39 | ||||
-rw-r--r-- | modules/caddyhttp/fileserver/staticfiles_test.go | 73 |
2 files changed, 95 insertions, 17 deletions
diff --git a/modules/caddyhttp/fileserver/staticfiles.go b/modules/caddyhttp/fileserver/staticfiles.go index d6cf4d6..735352b 100644 --- a/modules/caddyhttp/fileserver/staticfiles.go +++ b/modules/caddyhttp/fileserver/staticfiles.go @@ -329,28 +329,37 @@ func sanitizedPathJoin(root, reqPath string) string { // fileHidden returns true if filename is hidden // according to the hide list. func fileHidden(filename string, hide []string) bool { - nameOnly := filepath.Base(filename) sep := string(filepath.Separator) + var components []string for _, h := range hide { - // assuming h is a glob/shell-like pattern, - // use it to compare the whole file path; - // but if there is no separator in h, then - // just compare against the file's name - compare := filename if !strings.Contains(h, sep) { - compare = nameOnly - } - - hidden, err := filepath.Match(h, compare) - if err != nil { - // malformed pattern; fallback by checking prefix - if strings.HasPrefix(filename, h) { + // if there is no separator in h, then we assume the user + // wants to hide any files or folders that match that + // name; thus we have to compare against each component + // of the filename, e.g. hiding "bar" would hide "/bar" + // as well as "/foo/bar/baz" but not "/barstool". + if len(components) == 0 { + components = strings.Split(filename, sep) + } + for _, c := range components { + if c == h { + return true + } + } + } else if strings.HasPrefix(filename, h) { + // otherwise, if there is a separator in h, and + // filename is exactly prefixed with h, then we + // can do a prefix match so that "/foo" matches + // "/foo/bar" but not "/foobar". + withoutPrefix := strings.TrimPrefix(filename, h) + if strings.HasPrefix(withoutPrefix, sep) { return true } } - if hidden { - // file name or path matches hide pattern + + // in the general case, a glob match will suffice + if hidden, _ := filepath.Match(h, filename); hidden { return true } } diff --git a/modules/caddyhttp/fileserver/staticfiles_test.go b/modules/caddyhttp/fileserver/staticfiles_test.go index 73762c7..f074318 100644 --- a/modules/caddyhttp/fileserver/staticfiles_test.go +++ b/modules/caddyhttp/fileserver/staticfiles_test.go @@ -93,9 +93,78 @@ func TestSanitizedPathJoin(t *testing.T) { } actual := sanitizedPathJoin(tc.inputRoot, u.Path) if actual != tc.expect { - t.Errorf("Test %d: [%s %s] => %s (expected %s)", i, tc.inputRoot, tc.inputPath, actual, tc.expect) + t.Errorf("Test %d: [%s %s] => %s (expected %s)", + i, tc.inputRoot, tc.inputPath, actual, tc.expect) } } } -// TODO: test fileHidden +func TestFileHidden(t *testing.T) { + for i, tc := range []struct { + inputHide []string + inputPath string + expect bool + }{ + { + inputHide: nil, + inputPath: "", + expect: false, + }, + { + inputHide: []string{".gitignore"}, + inputPath: "/.gitignore", + expect: true, + }, + { + inputHide: []string{".git"}, + inputPath: "/.gitignore", + expect: false, + }, + { + inputHide: []string{"/.git"}, + inputPath: "/.gitignore", + expect: false, + }, + { + inputHide: []string{".git"}, + inputPath: "/.git", + expect: true, + }, + { + inputHide: []string{".git"}, + inputPath: "/.git/foo", + expect: true, + }, + { + inputHide: []string{".git"}, + inputPath: "/foo/.git/bar", + expect: true, + }, + { + inputHide: []string{"/prefix"}, + inputPath: "/prefix/foo", + expect: true, + }, + { + inputHide: []string{"/foo/*/bar"}, + inputPath: "/foo/asdf/bar", + expect: true, + }, + { + inputHide: []string{"/foo"}, + inputPath: "/foo", + expect: true, + }, + { + inputHide: []string{"/foo"}, + inputPath: "/foobar", + expect: false, + }, + } { + actual := fileHidden(tc.inputPath, tc.inputHide) + if actual != tc.expect { + t.Errorf("Test %d: Is %s hidden in %v? Got %t but expected %t", + i, tc.inputPath, tc.inputHide, actual, tc.expect) + } + } +} |