// An empty Dir is treated as ".".
type Dir string
-// mapDirOpenError maps the provided non-nil error from opening name
+// mapOpenError maps the provided non-nil error from opening name
// to a possibly better non-nil error. In particular, it turns OS-specific errors
-// about opening files in non-directories into fs.ErrNotExist. See Issue 18984.
-func mapDirOpenError(originalErr error, name string) error {
+// about opening files in non-directories into fs.ErrNotExist. See Issues 18984 and 49552.
+func mapOpenError(originalErr error, name string, sep rune, stat func(string) (fs.FileInfo, error)) error {
if errors.Is(originalErr, fs.ErrNotExist) || errors.Is(originalErr, fs.ErrPermission) {
return originalErr
}
- parts := strings.Split(name, string(filepath.Separator))
+ parts := strings.Split(name, string(sep))
for i := range parts {
if parts[i] == "" {
continue
}
- fi, err := os.Stat(strings.Join(parts[:i+1], string(filepath.Separator)))
+ fi, err := stat(strings.Join(parts[:i+1], string(sep)))
if err != nil {
return originalErr
}
fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
f, err := os.Open(fullName)
if err != nil {
- return nil, mapDirOpenError(err, fullName)
+ return nil, mapOpenError(err, fullName, filepath.Separator, os.Stat)
}
return f, nil
}
}
file, err := f.fsys.Open(name)
if err != nil {
- return nil, err
+ return nil, mapOpenError(err, name, '/', func(path string) (fs.FileInfo, error) {
+ return fs.Stat(f.fsys, path)
+ })
}
return ioFile{file}, nil
}
}
}
-// Issue 18984: tests that requests for paths beyond files return not-found errors
+// Issues 18984, 49552: tests that requests for paths beyond files return not-found errors
func TestFileServerNotDirError(t *testing.T) {
defer afterTest(t)
- ts := httptest.NewServer(FileServer(Dir("testdata")))
+ t.Run("Dir", func(t *testing.T) {
+ testFileServerNotDirError(t, func(path string) FileSystem { return Dir(path) })
+ })
+ t.Run("FS", func(t *testing.T) {
+ testFileServerNotDirError(t, func(path string) FileSystem { return FS(os.DirFS(path)) })
+ })
+}
+
+func testFileServerNotDirError(t *testing.T, newfs func(string) FileSystem) {
+ ts := httptest.NewServer(FileServer(newfs("testdata")))
defer ts.Close()
res, err := Get(ts.URL + "/index.html/not-a-file")
t.Errorf("StatusCode = %v; want 404", res.StatusCode)
}
- test := func(name string, dir Dir) {
+ test := func(name string, fsys FileSystem) {
t.Run(name, func(t *testing.T) {
- _, err = dir.Open("/index.html/not-a-file")
+ _, err = fsys.Open("/index.html/not-a-file")
if err == nil {
t.Fatal("err == nil; want != nil")
}
errors.Is(err, fs.ErrNotExist))
}
- _, err = dir.Open("/index.html/not-a-dir/not-a-file")
+ _, err = fsys.Open("/index.html/not-a-dir/not-a-file")
if err == nil {
t.Fatal("err == nil; want != nil")
}
t.Fatal("get abs path:", err)
}
- test("RelativePath", Dir("testdata"))
- test("AbsolutePath", Dir(absPath))
+ test("RelativePath", newfs("testdata"))
+ test("AbsolutePath", newfs(absPath))
}
func TestFileServerCleanPath(t *testing.T) {