mirror of https://github.com/golang/go.git
net/http: http.FileServer returns 404 when a path is invalid or unsafe
This commit is contained in:
parent
350118666d
commit
ed93ac5f29
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,6 +234,31 @@ func TestServeFile_DotDot(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestServeFile_InvalidUnsafePath(t *testing.T) {
|
||||
tests := []struct {
|
||||
req string
|
||||
wantStatus int
|
||||
}{
|
||||
{"/testdata/file", 200},
|
||||
{"/%00/file", 404},
|
||||
{"/file%00", 404},
|
||||
{"/%00", 404},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + tt.req + " HTTP/1.1\r\nHost: foo\r\n\r\n")))
|
||||
if err != nil {
|
||||
t.Errorf("bad request %q: %v", tt.req, err)
|
||||
continue
|
||||
}
|
||||
rec := httptest.NewRecorder()
|
||||
ServeFile(rec, req, "testdata/file")
|
||||
if rec.Code != tt.wantStatus {
|
||||
t.Logf("%v", rec.Result())
|
||||
t.Errorf("for request %q, status = %d; want %d", tt.req, rec.Code, tt.wantStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that this doesn't panic. (Issue 30165)
|
||||
func TestServeFileDirPanicEmptyPath(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
|
|
@ -733,6 +758,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
|
||||
|
|
|
|||
Loading…
Reference in New Issue