Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 10, 23:45 UTC
fileserver: preserve root directory matching in try_files (#8391)
Zen Dodd committed
Nov 10, 2026 at 18:54 UTC
3e05c4ddf002a76c9985e7b89c0b613230e774ec
3 files changed
+39
-1
caddytest/integration/try_files_test.go
+26
@@ -46,6 +46,32 @@ func TestTryFilesErrorCodeAfterQueryItem(t *testing.T) {
46
tester.AssertResponseCode(req, http.StatusNotFound)
47
}
48
49
+func TestTryFilesMatchesSiteRootDirectory(t *testing.T) {
50
+ root := t.TempDir()
51
+ if err := os.WriteFile(filepath.Join(root, "index.html"), []byte("root"), 0o600); err != nil {
52
+ t.Fatal(err)
53
+ }
54
+
55
+ tester := caddytest.NewTester(t)
56
+ tester.InitServer(fmt.Sprintf(`
57
+ {
58
+ skip_install_trust
59
+ admin localhost:2999
60
+ http_port 9080
61
+ grace_period 1ns
62
+ }
63
+ http://localhost:9080 {
64
+ root * %q
65
+ route {
66
+ try_files {path} {path}/ =404
67
+ file_server
68
+ }
69
+ }
70
+ `, filepath.ToSlash(root)), "caddyfile")
71
+
72
+ tester.AssertGetResponse("http://localhost:9080/", http.StatusOK, "root")
73
+}
74
+
75
func TestSkippedGroupedRouteKeepsRegexpCapture(t *testing.T) {
76
tester := caddytest.NewTester(t)
77
tester.InitServer(`
modules/caddyhttp/fileserver/matcher.go
+7
-1
@@ -610,9 +610,15 @@ func (m MatchFile) cleanSplit(pattern, expanded string) (beforeSplit, afterSplit
610
cleaned = "."
611
}
612
beforeSplit, afterSplit = m.firstSplit(cleaned)
613
+ patternHasTrailingSlash := strings.HasSuffix(pattern, "/")
614
+ // SanitizedPathJoin cleans the doubled slash but uses it to preserve
615
+ // the filesystem separator after the site root.
616
+ if beforeSplit == "/" && patternHasTrailingSlash {
617
+ beforeSplit += "/"
618
+ }
619
620
// with "{path}", a request for "/dir/" falls through to the next entry (e.g. "{path}/index.php")
615
- if beforeSplit != "/" && strings.HasSuffix(beforeSplit, "/") && !strings.HasSuffix(pattern, "/") {
621
+ if beforeSplit != "/" && strings.HasSuffix(beforeSplit, "/") && !patternHasTrailingSlash {
622
return "", "", false
623
}
624
return beforeSplit, afterSplit, true
modules/caddyhttp/fileserver/matcher_test.go
+6
@@ -63,6 +63,12 @@ func TestFileMatcher(t *testing.T) {
63
})
64
65
for i, tc := range []testCase{
66
+ {
67
+ path: "/",
68
+ expectedPath: "/",
69
+ expectedType: "directory",
70
+ matched: true,
71
+ },
72
{
73
path: "/.env",
74
expectedPath: "/.env",