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
|
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
|
// Open implements [FileSystem] using [os.Open], opening files for reading rooted
|
||||||
// and relative to the directory d.
|
// and relative to the directory d.
|
||||||
func (d Dir) Open(name string) (File, error) {
|
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)
|
path, err := filepath.Localize(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("http: invalid or unsafe file path")
|
return nil, errInvalidUnsafePath
|
||||||
}
|
}
|
||||||
dir := string(d)
|
dir := string(d)
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
|
|
@ -768,6 +773,9 @@ func toHTTPError(err error) (msg string, httpStatus int) {
|
||||||
if errors.Is(err, fs.ErrPermission) {
|
if errors.Is(err, fs.ErrPermission) {
|
||||||
return "403 Forbidden", StatusForbidden
|
return "403 Forbidden", StatusForbidden
|
||||||
}
|
}
|
||||||
|
if errors.Is(err, errInvalidUnsafePath) {
|
||||||
|
return "404 page not found", StatusNotFound
|
||||||
|
}
|
||||||
// Default:
|
// Default:
|
||||||
return "500 Internal Server Error", StatusInternalServerError
|
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)
|
// Tests that this doesn't panic. (Issue 30165)
|
||||||
func TestServeFileDirPanicEmptyPath(t *testing.T) {
|
func TestServeFileDirPanicEmptyPath(t *testing.T) {
|
||||||
rec := httptest.NewRecorder()
|
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) { run(t, testFileServerNamesEscape) }
|
||||||
func testFileServerNamesEscape(t *testing.T, mode testMode) {
|
func testFileServerNamesEscape(t *testing.T, mode testMode) {
|
||||||
ts := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts
|
ts := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue