diff options
| author | Grégoire Lodi <pro@lodi.me> | 2025-03-05 09:44:46 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-03-05 11:26:39 -0800 |
| commit | 061efaa8a761458eaa41119ffd59033738cf141c (patch) | |
| tree | 9b9d168aeba7ca7cc5fd596352dac45a6a4f425d /src/net/http | |
| parent | 37026a7c563c580bef0fac1e5b60e9498650e3a2 (diff) | |
| download | go-061efaa8a761458eaa41119ffd59033738cf141c.tar.xz | |
net/http: make http.FileServer return 404 when a path is invalid/unsafe
This PR adds error handling in net/http toHTTPError to return a 404
instead of a 500 when net/http fs.Dir.Open throws the error http:
invalid or unsafe file path.
Fixes #72091
Change-Id: I7941c8fca5160a4a82732dc1d05b9b95eac84fbf
GitHub-Last-Rev: 04b5019dfb629820621f3776d6f22fd754171565
GitHub-Pull-Request: golang/go#72108
Reviewed-on: https://go-review.googlesource.com/c/go/+/654975
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Damien Neil <dneil@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Diffstat (limited to 'src/net/http')
| -rw-r--r-- | src/net/http/fs.go | 10 | ||||
| -rw-r--r-- | src/net/http/fs_test.go | 21 |
2 files changed, 30 insertions, 1 deletions
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 |
