Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http: http.FileServer returns 500 on "not a directory" error #49552

Open
jba opened this issue Nov 12, 2021 · 3 comments
Open

net/http: http.FileServer returns 500 on "not a directory" error #49552

jba opened this issue Nov 12, 2021 · 3 comments

Comments

@jba
Copy link
Contributor

@jba jba commented Nov 12, 2021

go version devel +b7a85e000

linux/amd64

What did you do?

Tried to serve shared/icon/favicon.ico/static/shared/icon/favicon.ico with http.FileServer(http.FS(MY_STATIC_PATH)).

What did you expect to see?

404

What did you see instead?

500

Diagnosis

The toHTTPError function (in net/http/fs.go) treats anything other than ErrNotExist and ErrPermission as a 500. But here we have an invalid path—a path that doesn't exist—that happens to go through the existing file shared/icon/favicon.ico. It should treat that the same as ErrNotExist.

@odeke-em
Copy link
Member

@odeke-em odeke-em commented Nov 13, 2021

Thank you for filing this issue @jba and great to catch you here!

I have some code for you that if you minimally tweak can perhaps make your issue even more actionable and it can also serve as a test when/if the fix is issued. Mine correctly issues a 404. Please see

package issue49552

import (
	"net/http"
	"net/http/httptest"
	"net/http/httputil"
	"os"
	"path/filepath"
	"testing"
)

func TestIssue49552(t *testing.T) {
	tmpDir := t.TempDir()
	// 1. Setup the scaffolding mentioned in the issue.
	staticDirPath := filepath.Join(tmpDir, "shared")
	if err := os.MkdirAll(staticDirPath, 0755); err != nil {
		t.Fatal(err)
	}
	srv := http.FileServer(http.Dir("./shared"))
	cst := httptest.NewServer(srv)
	defer cst.Close()

	res, err := cst.Client().Get(cst.URL + "/icon/favicon.ico/static/shared/icon/favicon.ico")
	if err != nil {
		t.Fatalf("Failed to make the request: %v", err)
	}
	defer res.Body.Close()

	blob, err := httputil.DumpResponse(res, true)
	if err != nil {
		t.Fatal(err)
	}
	println(string(blob))
	if g, w := res.StatusCode, 404; g != w {
		t.Fatalf("Error code mismatch: got %d, want %d", g, w)
	}
}

which produces

$ go test
HTTP/1.1 404 Not Found
Content-Length: 19
Content-Type: text/plain; charset=utf-8
Date: Sat, 13 Nov 2021 23:51:47 GMT
X-Content-Type-Options: nosniff

404 page not found

PASS
ok  	github.com/odeke-em/bugs/golang/49552	0.186s

Loading

@cagedmantis cagedmantis added this to the Backlog milestone Nov 15, 2021
@neild
Copy link
Contributor

@neild neild commented Nov 15, 2021

If you use http.FileServer(http.Dir("dir")), you get a 404 error if a component of the path prefix is not a directory.

If you use http.FileServer(http.FS(os.DirFS("dir"))), you get a 500.

Perhaps ENOTDIR should compare as equivalent to fs.ErrNotExist, since it is a more specific case of a file not existing.

Loading

@gopherbot
Copy link

@gopherbot gopherbot commented Nov 15, 2021

Change https://golang.org/cl/364074 mentions this issue: syscall: make ENOTDIR match fs.ErrNotExist

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants