diff --git a/server/middlewares.go b/server/middlewares.go index a373a69f7..92f8d8926 100644 --- a/server/middlewares.go +++ b/server/middlewares.go @@ -3,13 +3,14 @@ package server import ( "fmt" "net/http" + "strings" "time" "github.com/deluan/navidrome/log" "github.com/go-chi/chi/middleware" ) -func RequestLogger(next http.Handler) http.Handler { +func requestLogger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { scheme := "http" if r.TLS != nil { @@ -44,3 +45,16 @@ func RequestLogger(next http.Handler) http.Handler { } }) } + +func robotsTXT(fs http.FileSystem) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if strings.HasSuffix(r.URL.Path, "/robots.txt") { + r.URL.Path = "/robots.txt" + http.FileServer(fs).ServeHTTP(w, r) + } else { + next.ServeHTTP(w, r) + } + }) + } +} diff --git a/server/middlewares_test.go b/server/middlewares_test.go new file mode 100644 index 000000000..a6eea2762 --- /dev/null +++ b/server/middlewares_test.go @@ -0,0 +1,50 @@ +package server + +import ( + "net/http" + "net/http/httptest" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("middlewares", func() { + var nextCalled bool + next := func(w http.ResponseWriter, r *http.Request) { + nextCalled = true + } + Describe("robotsTXT", func() { + BeforeEach(func() { + nextCalled = false + }) + + It("returns the robot.txt when requested from root", func() { + r := httptest.NewRequest("GET", "/robots.txt", nil) + w := httptest.NewRecorder() + + robotsTXT(http.Dir("tests/fixtures"))(http.HandlerFunc(next)).ServeHTTP(w, r) + + Expect(nextCalled).To(BeFalse()) + Expect(w.Body.String()).To(HavePrefix("User-agent:")) + }) + + It("allows prefixes", func() { + r := httptest.NewRequest("GET", "/app/robots.txt", nil) + w := httptest.NewRecorder() + + robotsTXT(http.Dir("tests/fixtures"))(http.HandlerFunc(next)).ServeHTTP(w, r) + + Expect(nextCalled).To(BeFalse()) + Expect(w.Body.String()).To(HavePrefix("User-agent:")) + }) + + It("passes through requests for other files", func() { + r := httptest.NewRequest("GET", "/this_is_not_a_robots.txt_file", nil) + w := httptest.NewRecorder() + + robotsTXT(http.Dir("tests/fixtures"))(http.HandlerFunc(next)).ServeHTTP(w, r) + + Expect(nextCalled).To(BeTrue()) + }) + }) +}) diff --git a/server/server.go b/server/server.go index 5a261da4c..50806d775 100644 --- a/server/server.go +++ b/server/server.go @@ -5,6 +5,7 @@ import ( "path" "time" + "github.com/deluan/navidrome/assets" "github.com/deluan/navidrome/conf" "github.com/deluan/navidrome/consts" "github.com/deluan/navidrome/log" @@ -39,7 +40,7 @@ func (a *Server) MountRouter(urlPath string, subRouter Handler) { log.Info("Mounting routes", "path", urlPath) subRouter.Setup(urlPath) a.router.Group(func(r chi.Router) { - r.Use(RequestLogger) + r.Use(requestLogger) r.Mount(urlPath, subRouter) }) } @@ -58,7 +59,8 @@ func (a *Server) initRoutes() { r.Use(middleware.Recoverer) r.Use(middleware.Compress(5, "application/xml", "application/json", "application/javascript")) r.Use(middleware.Heartbeat("/ping")) - r.Use(InjectLogger) + r.Use(injectLogger) + r.Use(robotsTXT(assets.AssetFile())) indexHtml := path.Join(conf.Server.BaseURL, consts.URLPathUI, "index.html") r.Get("/*", func(w http.ResponseWriter, r *http.Request) { @@ -87,7 +89,7 @@ func (a *Server) initScanner() { }() } -func InjectLogger(next http.Handler) http.Handler { +func injectLogger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() ctx = log.NewContext(r.Context(), "requestId", ctx.Value(middleware.RequestIDKey)) diff --git a/server/server_suite_test.go b/server/server_suite_test.go new file mode 100644 index 000000000..5786824c0 --- /dev/null +++ b/server/server_suite_test.go @@ -0,0 +1,17 @@ +package server + +import ( + "testing" + + "github.com/deluan/navidrome/log" + "github.com/deluan/navidrome/tests" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestSubsonicApi(t *testing.T) { + tests.Init(t, false) + log.SetLevel(log.LevelCritical) + RegisterFailHandler(Fail) + RunSpecs(t, "Server Suite") +} diff --git a/tests/fixtures/robots.txt b/tests/fixtures/robots.txt new file mode 100644 index 000000000..5a8c263b3 --- /dev/null +++ b/tests/fixtures/robots.txt @@ -0,0 +1,4 @@ +User-agent: bingbot +Disallow: /manifest.json + +User-agent: *