ServeFromSubPath: Redirect to URL with subpath when subpath missing (#66724)

* ServeFromSubPath: Redirect to URL with subpath when subpath missing

* Review fixes

* Added tests

* Use constant

* change to useMiddleware

* Update pkg/middleware/subpath_redirect.go

---------

Co-authored-by: Carl Bergquist <carl.bergquist@gmail.com>
This commit is contained in:
Torkel Ödegaard
2023-04-24 09:55:55 +02:00
committed by GitHub
parent 2767d5b1c2
commit 57701fd2f2
4 changed files with 74 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
package middleware
import (
"fmt"
"net/http"
"strings"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
)
// SubPathRedirect Redirects URLs that are missing the configured subpath to an URL that contains the subpath.
func SubPathRedirect(cfg *setting.Cfg) web.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
// Direct to url with subpath if the request is missing the subpath and is not an API request.
if !strings.HasPrefix(req.RequestURI, cfg.AppSubURL) && !strings.HasPrefix(req.RequestURI, "/api") {
newURL := fmt.Sprintf("%s%s", cfg.AppURL, strings.TrimPrefix(req.RequestURI, "/"))
http.Redirect(rw, req, newURL, http.StatusMovedPermanently)
return
}
next.ServeHTTP(rw, req)
})
}
}

View File

@@ -0,0 +1,43 @@
package middleware
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSubPathRedirect(t *testing.T) {
testSubPathRedirect(t, "/", "http://localhost:3000/subpath/")
testSubPathRedirect(t, "/admin/my/page", "http://localhost:3000/subpath/admin/my/page")
testSubPathRedirect(t, "/api/users", "")
}
func testSubPathRedirect(t *testing.T, url string, expectedRedirect string) {
middlewareScenario(t, "GET url without subpath", func(t *testing.T, sc *scenarioContext) {
sc.cfg.AppSubURL = "/subpath"
sc.cfg.AppURL = "http://localhost:3000/subpath/"
sc.m.UseMiddleware(SubPathRedirect(sc.cfg))
sc.m.Get("/api/users", sc.defaultHandler)
sc.fakeReqWithParams("GET", url, map[string]string{}).exec()
if expectedRedirect != "" {
assert.Equal(t, 301, sc.resp.Code)
// nolint:bodyclose
resp := sc.resp.Result()
t.Cleanup(func() {
err := resp.Body.Close()
assert.NoError(t, err)
})
redirectURL, err := resp.Location()
require.NoError(t, err)
assert.Equal(t, expectedRedirect, redirectURL.String())
} else {
assert.Equal(t, 200, sc.resp.Code)
}
})
}

View File

@@ -99,7 +99,10 @@ func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map
for k, v := range queryParams {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
req.RequestURI = req.URL.RequestURI()
require.NoError(sc.t, err)
reqCtx := &contextmodel.ReqContext{