From 237747718870a43e47462c9b088681fb1cc1f817 Mon Sep 17 00:00:00 2001 From: Rob Watson Date: Sat, 8 Jan 2022 12:16:30 +0100 Subject: [PATCH] Disable directory listings in http.FileServer. Closes #6 --- backend/server/middleware.go | 18 +++++++++ backend/server/middleware_test.go | 66 +++++++++++++++++++++++++++++++ backend/server/server.go | 3 ++ 3 files changed, 87 insertions(+) create mode 100644 backend/server/middleware.go create mode 100644 backend/server/middleware_test.go diff --git a/backend/server/middleware.go b/backend/server/middleware.go new file mode 100644 index 0000000..e51c700 --- /dev/null +++ b/backend/server/middleware.go @@ -0,0 +1,18 @@ +package server + +import ( + "net/http" + "strings" +) + +// DisableDirectoryListings intercepts and responds with 404 to HTTP requests +// which would otherwise be served with a directory listing by http.FileServer. +func DisableDirectoryListings(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if strings.HasSuffix(r.URL.Path, "/") { + http.NotFound(w, r) + return + } + next.ServeHTTP(w, r) + }) +} diff --git a/backend/server/middleware_test.go b/backend/server/middleware_test.go new file mode 100644 index 0000000..c8ad361 --- /dev/null +++ b/backend/server/middleware_test.go @@ -0,0 +1,66 @@ +package server_test + +import ( + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "git.netflux.io/rob/clipper/server" + "github.com/stretchr/testify/assert" +) + +func TestDisableDirectoryListings(t *testing.T) { + testCases := []struct { + path string + wantStatus int + }{ + { + path: "/", + wantStatus: http.StatusNotFound, + }, + { + path: "/index.html", + wantStatus: http.StatusOK, + }, + { + path: "/foo", + wantStatus: http.StatusOK, + }, + { + path: "/foo/", + wantStatus: http.StatusNotFound, + }, + { + path: "/foo/bar", + wantStatus: http.StatusOK, + }, + { + path: "/foo/bar/", + wantStatus: http.StatusNotFound, + }, + { + path: "/foo/bar/baz", + wantStatus: http.StatusOK, + }, + { + path: "/foo/bar/baz/index.html", + wantStatus: http.StatusOK, + }, + } + + for _, tc := range testCases { + t.Run("path="+tc.path, func(t *testing.T) { + req := httptest.NewRequest("GET", tc.path, nil) + rec := httptest.NewRecorder() + + handler := server.DisableDirectoryListings(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + fmt.Fprintf(w, "Hello world") + })) + handler.ServeHTTP(rec, req) + + resp := rec.Result() + assert.Equal(t, tc.wantStatus, resp.StatusCode) + }) + } +} diff --git a/backend/server/server.go b/backend/server/server.go index a305d73..d3112a0 100644 --- a/backend/server/server.go +++ b/backend/server/server.go @@ -307,6 +307,9 @@ func Start(options Options) error { fileHandler = http.FileServer(http.Dir(options.Config.FileStoreHTTPRoot)) } + // Ensure http.FileServer does not serve directory listings. + fileHandler = DisableDirectoryListings(fileHandler) + httpServer := http.Server{ Addr: options.Config.BindAddr, ReadTimeout: options.Timeout,