summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/caddyhttp/fileserver/matcher.go20
-rw-r--r--modules/caddyhttp/fileserver/matcher_test.go63
2 files changed, 56 insertions, 27 deletions
diff --git a/modules/caddyhttp/fileserver/matcher.go b/modules/caddyhttp/fileserver/matcher.go
index 9144ca4..1844421 100644
--- a/modules/caddyhttp/fileserver/matcher.go
+++ b/modules/caddyhttp/fileserver/matcher.go
@@ -117,11 +117,13 @@ func (m *MatchFile) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.ArgErr()
}
m.TryPolicy = d.Val()
- case "split":
+ case "split_path":
m.SplitPath = d.RemainingArgs()
if len(m.SplitPath) == 0 {
return d.ArgErr()
}
+ default:
+ return d.Errf("unrecognized subdirective: %s", d.Val())
}
}
}
@@ -279,9 +281,8 @@ func strictFileExists(file string) bool {
// in the split value. Returns the path as-is if the
// path cannot be split.
func (m MatchFile) firstSplit(path string) string {
- lowerPath := strings.ToLower(path)
for _, split := range m.SplitPath {
- if idx := strings.Index(lowerPath, strings.ToLower(split)); idx > -1 {
+ if idx := indexFold(path, split); idx > -1 {
pos := idx + len(split)
// skip the split if it's not the final part of the filename
if pos != len(path) && !strings.HasPrefix(path[pos:], "/") {
@@ -293,6 +294,19 @@ func (m MatchFile) firstSplit(path string) string {
return path
}
+// There is no strings.IndexFold() function like there is strings.EqualFold(),
+// but we can use strings.EqualFold() to build our own case-insensitive
+// substring search (as of Go 1.14).
+func indexFold(haystack, needle string) int {
+ nlen := len(needle)
+ for i := 0; i+nlen < len(haystack); i++ {
+ if strings.EqualFold(haystack[i:i+nlen], needle) {
+ return i
+ }
+ }
+ return -1
+}
+
const (
tryPolicyFirstExist = "first_exist"
tryPolicyLargestSize = "largest_size"
diff --git a/modules/caddyhttp/fileserver/matcher_test.go b/modules/caddyhttp/fileserver/matcher_test.go
index aa84900..e3f2911 100644
--- a/modules/caddyhttp/fileserver/matcher_test.go
+++ b/modules/caddyhttp/fileserver/matcher_test.go
@@ -22,69 +22,84 @@ import (
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
)
-func TestPhpFileMatcher(t *testing.T) {
-
+func TestPHPFileMatcher(t *testing.T) {
for i, tc := range []struct {
- path string
+ path string
expectedPath string
- matched bool
+ matched bool
}{
{
- path: "/index.php",
+ path: "/index.php",
expectedPath: "/index.php",
- matched: true,
+ matched: true,
},
{
- path: "/index.php/somewhere",
+ path: "/index.php/somewhere",
expectedPath: "/index.php",
- matched: true,
+ matched: true,
},
{
- path: "/remote.php",
+ path: "/remote.php",
expectedPath: "/remote.php",
- matched: true,
+ matched: true,
},
{
- path: "/remote.php/somewhere",
+ path: "/remote.php/somewhere",
expectedPath: "/remote.php",
- matched: true,
+ matched: true,
},
{
- path: "/missingfile.php",
+ path: "/missingfile.php",
matched: false,
},
{
- path: "/notphp.php.txt",
+ path: "/notphp.php.txt",
expectedPath: "/notphp.php.txt",
- matched: true,
+ matched: true,
},
{
- path: "/notphp.php.txt/",
+ path: "/notphp.php.txt/",
expectedPath: "/notphp.php.txt",
- matched: true,
+ matched: true,
},
{
- path: "/notphp.php.txt.suffixed",
+ path: "/notphp.php.txt.suffixed",
matched: false,
},
{
- path: "/foo.php.php/index.php",
+ path: "/foo.php.php/index.php",
expectedPath: "/foo.php.php/index.php",
- matched: true,
+ matched: true,
+ },
+ {
+ path: "/foo.php.PHP/index.php",
+ expectedPath: "/foo.php.PHP/index.php",
+ matched: true,
+ },
+ {
+ // See https://github.com/caddyserver/caddy/issues/3623
+ path: "/%E2%C3",
+ expectedPath: "/%E2%C3",
+ matched: false,
},
} {
m := &MatchFile{
Root: "./testdata",
- TryFiles: []string{"{http.request.uri.path}"},
+ TryFiles: []string{"{http.request.uri.path}", "{http.request.uri.path}/index.php"},
SplitPath: []string{".php"},
}
- req := &http.Request{URL: &url.URL{Path: tc.path}}
+ u, err := url.Parse(tc.path)
+ if err != nil {
+ t.Fatalf("Test %d: parsing path: %v", i, err)
+ }
+
+ req := &http.Request{URL: u}
repl := caddyhttp.NewTestReplacer(req)
result := m.Match(req)
if result != tc.matched {
- t.Fatalf("Test %d: match bool result: %v, expected: %v", i, result, tc.matched)
+ t.Fatalf("Test %d: expected match=%t, got %t", i, tc.matched, result)
}
rel, ok := repl.Get("http.matchers.file.relative")
@@ -99,4 +114,4 @@ func TestPhpFileMatcher(t *testing.T) {
t.Fatalf("Test %d: actual path: %v, expected: %v", i, rel, tc.expectedPath)
}
}
-} \ No newline at end of file
+}