Skip to content

Commit 6df0957

Browse files
jbaodeke-em
authored andcommitted
net/http: map FS Open errors just like Dir
When an http.FileServer is given a path like file1/file2 where file1 exists but file2 does not, the proper HTTP status should be NotFound. Some OSes return a "not a directory" error instead, so this must be mapped to NotFound. That mapping was already being done for the Dir FileSystem implementation, as discussed in #18984. But it wasn't for the FS implementation. This CL does the same mapping for FS, by generalizing the function that did it for Dir. Fixes #49552 Change-Id: I61d6aa8ef101158e9674707d44e653f5dedbd040 Reviewed-on: https://go-review.googlesource.com/c/go/+/376874 Trust: Jonathan Amsterdam <[email protected]> Run-TryBot: Jonathan Amsterdam <[email protected]> Reviewed-by: Emmanuel Odeke <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 2639f2f commit 6df0957

File tree

2 files changed

+25
-14
lines changed

2 files changed

+25
-14
lines changed

src/net/http/fs.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,20 @@ import (
4242
// An empty Dir is treated as ".".
4343
type Dir string
4444

45-
// mapDirOpenError maps the provided non-nil error from opening name
45+
// mapOpenError maps the provided non-nil error from opening name
4646
// to a possibly better non-nil error. In particular, it turns OS-specific errors
47-
// about opening files in non-directories into fs.ErrNotExist. See Issue 18984.
48-
func mapDirOpenError(originalErr error, name string) error {
47+
// about opening files in non-directories into fs.ErrNotExist. See Issues 18984 and 49552.
48+
func mapOpenError(originalErr error, name string, sep rune, stat func(string) (fs.FileInfo, error)) error {
4949
if errors.Is(originalErr, fs.ErrNotExist) || errors.Is(originalErr, fs.ErrPermission) {
5050
return originalErr
5151
}
5252

53-
parts := strings.Split(name, string(filepath.Separator))
53+
parts := strings.Split(name, string(sep))
5454
for i := range parts {
5555
if parts[i] == "" {
5656
continue
5757
}
58-
fi, err := os.Stat(strings.Join(parts[:i+1], string(filepath.Separator)))
58+
fi, err := stat(strings.Join(parts[:i+1], string(sep)))
5959
if err != nil {
6060
return originalErr
6161
}
@@ -79,7 +79,7 @@ func (d Dir) Open(name string) (File, error) {
7979
fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
8080
f, err := os.Open(fullName)
8181
if err != nil {
82-
return nil, mapDirOpenError(err, fullName)
82+
return nil, mapOpenError(err, fullName, filepath.Separator, os.Stat)
8383
}
8484
return f, nil
8585
}
@@ -759,7 +759,9 @@ func (f ioFS) Open(name string) (File, error) {
759759
}
760760
file, err := f.fsys.Open(name)
761761
if err != nil {
762-
return nil, err
762+
return nil, mapOpenError(err, name, '/', func(path string) (fs.FileInfo, error) {
763+
return fs.Stat(f.fsys, path)
764+
})
763765
}
764766
return ioFile{file}, nil
765767
}

src/net/http/fs_test.go

+16-7
Original file line numberDiff line numberDiff line change
@@ -1244,10 +1244,19 @@ func TestLinuxSendfileChild(*testing.T) {
12441244
}
12451245
}
12461246

1247-
// Issue 18984: tests that requests for paths beyond files return not-found errors
1247+
// Issues 18984, 49552: tests that requests for paths beyond files return not-found errors
12481248
func TestFileServerNotDirError(t *testing.T) {
12491249
defer afterTest(t)
1250-
ts := httptest.NewServer(FileServer(Dir("testdata")))
1250+
t.Run("Dir", func(t *testing.T) {
1251+
testFileServerNotDirError(t, func(path string) FileSystem { return Dir(path) })
1252+
})
1253+
t.Run("FS", func(t *testing.T) {
1254+
testFileServerNotDirError(t, func(path string) FileSystem { return FS(os.DirFS(path)) })
1255+
})
1256+
}
1257+
1258+
func testFileServerNotDirError(t *testing.T, newfs func(string) FileSystem) {
1259+
ts := httptest.NewServer(FileServer(newfs("testdata")))
12511260
defer ts.Close()
12521261

12531262
res, err := Get(ts.URL + "/index.html/not-a-file")
@@ -1259,9 +1268,9 @@ func TestFileServerNotDirError(t *testing.T) {
12591268
t.Errorf("StatusCode = %v; want 404", res.StatusCode)
12601269
}
12611270

1262-
test := func(name string, dir Dir) {
1271+
test := func(name string, fsys FileSystem) {
12631272
t.Run(name, func(t *testing.T) {
1264-
_, err = dir.Open("/index.html/not-a-file")
1273+
_, err = fsys.Open("/index.html/not-a-file")
12651274
if err == nil {
12661275
t.Fatal("err == nil; want != nil")
12671276
}
@@ -1270,7 +1279,7 @@ func TestFileServerNotDirError(t *testing.T) {
12701279
errors.Is(err, fs.ErrNotExist))
12711280
}
12721281

1273-
_, err = dir.Open("/index.html/not-a-dir/not-a-file")
1282+
_, err = fsys.Open("/index.html/not-a-dir/not-a-file")
12741283
if err == nil {
12751284
t.Fatal("err == nil; want != nil")
12761285
}
@@ -1286,8 +1295,8 @@ func TestFileServerNotDirError(t *testing.T) {
12861295
t.Fatal("get abs path:", err)
12871296
}
12881297

1289-
test("RelativePath", Dir("testdata"))
1290-
test("AbsolutePath", Dir(absPath))
1298+
test("RelativePath", newfs("testdata"))
1299+
test("AbsolutePath", newfs(absPath))
12911300
}
12921301

12931302
func TestFileServerCleanPath(t *testing.T) {

0 commit comments

Comments
 (0)