diff --git a/cmd/karma/main.go b/cmd/karma/main.go index 91ba8cd3b..729f5a43d 100644 --- a/cmd/karma/main.go +++ b/cmd/karma/main.go @@ -60,15 +60,14 @@ var ( func getViewURL(sub string) string { var fixedSub string fixedSub = sub - if !strings.HasPrefix(sub, "/") { + if sub != "" && !strings.HasPrefix(sub, "/") { fixedSub = "/" + sub } var fixedPrefix string - fixedPrefix = config.Config.Listen.Prefix - if config.Config.Listen.Prefix != "" && !strings.HasPrefix(config.Config.Listen.Prefix, "/") { - fixedPrefix = "/" + config.Config.Listen.Prefix - } + fixedPrefix = strings.TrimPrefix(config.Config.Listen.Prefix, "/") + fixedPrefix = strings.TrimSuffix(fixedPrefix, "/") + fixedPrefix = "/" + fixedPrefix + "/" u := path.Join(fixedPrefix, fixedSub) if strings.HasSuffix(fixedSub, "/") && !strings.HasSuffix(u, "/") { @@ -127,6 +126,9 @@ func setupRouter(router *chi.Mux, historyPoller *historyPoller) { router.Use(basicAuth(users, allowAuthBypass)) } + if config.Config.Listen.Prefix != "/" { + router.Get(getViewURL(""), redirectIndex) + } router.Get(getViewURL("/"), index) router.Get(getViewURL("/health"), pong) router.Get(getViewURL("/robots.txt"), robots) diff --git a/cmd/karma/views.go b/cmd/karma/views.go index 143d9e648..6da1801d5 100644 --- a/cmd/karma/views.go +++ b/cmd/karma/views.go @@ -94,6 +94,10 @@ func pushPath(w http.ResponseWriter, path string) { } } +func redirectIndex(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, r.URL.Path+"/", http.StatusMovedPermanently) +} + func index(w http.ResponseWriter, r *http.Request) { noCache(w) pushPath(w, getViewURL("/custom.css")) diff --git a/cmd/karma/views_test.go b/cmd/karma/views_test.go index 3caf218c5..1df4b6543 100644 --- a/cmd/karma/views_test.go +++ b/cmd/karma/views_test.go @@ -103,28 +103,102 @@ func TestHealthPrefix(t *testing.T) { } func TestIndex(t *testing.T) { - mockConfig() - r := testRouter() - setupRouter(r, nil) - req := httptest.NewRequest("GET", "/", nil) - resp := httptest.NewRecorder() - r.ServeHTTP(resp, req) - if resp.Code != http.StatusOK { - t.Errorf("GET / returned status %d", resp.Code) + type testCaseT struct { + prefix string + request string + status int + redirect string } -} -func TestIndexPrefix(t *testing.T) { - os.Setenv("LISTEN_PREFIX", "/prefix") - defer os.Unsetenv("LISTEN_PREFIX") - mockConfig() - r := testRouter() - setupRouter(r, nil) - req := httptest.NewRequest("GET", "/prefix/", nil) - resp := httptest.NewRecorder() - r.ServeHTTP(resp, req) - if resp.Code != http.StatusOK { - t.Errorf("GET /prefix/ returned status %d", resp.Code) + testCases := []testCaseT{ + { + prefix: "", + request: "/", + status: 200, + }, + { + prefix: "", + request: "/alerts.json", + status: 200, + }, + { + prefix: "/", + request: "/", + status: 200, + }, + { + prefix: "/", + request: "/alerts.json", + status: 200, + }, + { + prefix: "/prefix", + request: "/", + status: 404, + }, + { + prefix: "/prefix", + request: "/alerts.json", + status: 404, + }, + { + prefix: "/prefix", + request: "/prefix/", + status: 200, + }, + { + prefix: "/prefix", + request: "/prefix/alerts.json", + status: 200, + }, + { + prefix: "/prefix", + request: "/prefix", + status: 301, + redirect: "/prefix/", + }, + { + prefix: "/prefix/", + request: "/prefix", + status: 301, + redirect: "/prefix/", + }, + { + prefix: "/prefix/", + request: "/prefix/", + status: 200, + }, + { + prefix: "/prefix/", + request: "/prefix/alerts.json", + status: 200, + }, + } + + defer func() { + config.Config.Listen.Prefix = "/" + }() + + for _, tc := range testCases { + t.Run(fmt.Sprintf("prefix=%s request=%s status=%d", tc.prefix, tc.request, tc.status), func(t *testing.T) { + os.Setenv("LISTEN_PREFIX", tc.prefix) + defer os.Unsetenv("LISTEN_PREFIX") + mockConfig() + r := testRouter() + setupRouter(r, nil) + req := httptest.NewRequest("GET", tc.request, nil) + resp := httptest.NewRecorder() + r.ServeHTTP(resp, req) + if resp.Code != tc.status { + t.Errorf("GET %s returned status %d, expected %d", tc.request, resp.Code, tc.status) + return + } + if resp.Code/100 == 3 && tc.status/100 == 3 { + if resp.Header().Get("Location") != tc.redirect { + t.Errorf("GET %s returned redirect to %s, expected %s", tc.request, resp.Header().Get("Location"), tc.redirect) + } + } + }) } }