diff --git a/src/net/http/fs.go b/src/net/http/fs.go index 48ba05a664..92bd94f72d 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -67,6 +67,11 @@ func mapOpenError(originalErr error, name string, sep rune, stat func(string) (f return originalErr } +// errInvalidUnsafePath is returned by Dir.Open when the call to +// filepath.Localize fails. filepath.Localize returns an error if the path +// cannot be represented by the operating system. +var errInvalidUnsafePath = errors.New("http: invalid or unsafe file path") + // Open implements [FileSystem] using [os.Open], opening files for reading rooted // and relative to the directory d. func (d Dir) Open(name string) (File, error) { @@ -76,7 +81,7 @@ func (d Dir) Open(name string) (File, error) { } path, err := filepath.Localize(path) if err != nil { - return nil, errors.New("http: invalid or unsafe file path") + return nil, errInvalidUnsafePath } dir := string(d) if dir == "" { @@ -768,6 +773,9 @@ func toHTTPError(err error) (msg string, httpStatus int) { if errors.Is(err, fs.ErrPermission) { return "403 Forbidden", StatusForbidden } + if errors.Is(err, errInvalidUnsafePath) { + return "404 page not found", StatusNotFound + } // Default: return "500 Internal Server Error", StatusInternalServerError } diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go index 3149ca35ac..9b34ad080e 100644 --- a/src/net/http/fs_test.go +++ b/src/net/http/fs_test.go @@ -733,6 +733,27 @@ func testFileServerZeroByte(t *testing.T, mode testMode) { } } +func TestFileServerNullByte(t *testing.T) { run(t, testFileServerNullByte) } +func testFileServerNullByte(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts + + for _, path := range []string{ + "/file%00", + "/%00", + "/file/qwe/%00", + } { + res, err := ts.Client().Get(ts.URL + path) + if err != nil { + t.Fatal(err) + } + res.Body.Close() + if res.StatusCode != 404 { + t.Errorf("Get(%q): got status %v, want 404", path, res.StatusCode) + } + + } +} + func TestFileServerNamesEscape(t *testing.T) { run(t, testFileServerNamesEscape) } func testFileServerNamesEscape(t *testing.T, mode testMode) { ts := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts