diff --git a/pkg/service/server.go b/pkg/service/server.go index 0c298467e..30222079e 100644 --- a/pkg/service/server.go +++ b/pkg/service/server.go @@ -102,6 +102,7 @@ func NewLivekitServer(conf *config.Config, // allow preflight to be cached for a day MaxAge: 86400, }), + negroni.HandlerFunc(RemoveDoubleSlashes), } if keyProvider != nil { middlewares = append(middlewares, NewAPIKeyAuthMiddleware(keyProvider)) diff --git a/pkg/service/utils.go b/pkg/service/utils.go index 7ce0e7bc4..db76e008a 100644 --- a/pkg/service/utils.go +++ b/pkg/service/utils.go @@ -20,6 +20,7 @@ import ( "net" "net/http" "regexp" + "strings" "github.com/livekit/protocol/logger" ) @@ -40,6 +41,13 @@ func boolValue(s string) bool { return s == "1" || s == "true" } +func RemoveDoubleSlashes(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + if strings.HasPrefix(r.URL.Path, "//") { + r.URL.Path = r.URL.Path[1:] + } + next(w, r) +} + func IsValidDomain(domain string) bool { domainRegexp := regexp.MustCompile(`^(?i)[a-z0-9-]+(\.[a-z0-9-]+)+\.?$`) return domainRegexp.MatchString(domain) diff --git a/test/singlenode_test.go b/test/singlenode_test.go index 9512b92b1..5b68ad49d 100644 --- a/test/singlenode_test.go +++ b/test/singlenode_test.go @@ -376,6 +376,20 @@ func TestSingleNodeCORS(t *testing.T) { require.Equal(t, "testhost.com", res.Header.Get("Access-Control-Allow-Origin")) } +func TestSingleNodeDoubleSlash(t *testing.T) { + if testing.Short() { + t.SkipNow() + return + } + s, finish := setupSingleNodeTest("TestSingleNodeDoubleSlash") + defer finish() + // client contains trailing slash in URL, causing path to contain double // + // without our middleware, this would cause a 302 redirect + roomClient = livekit.NewRoomServiceJSONClient(fmt.Sprintf("http://localhost:%d/", s.HTTPPort()), &http.Client{}) + _, err := roomClient.ListRooms(contextWithToken(listRoomToken()), &livekit.ListRoomsRequest{}) + require.NoError(t, err) +} + func TestPingPong(t *testing.T) { if testing.Short() { t.SkipNow()