@marcel91200 / caddy Mirror · read-only / commits / 3e05c4dd
Fork 0

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",