reitit
reitit copied to clipboard
redirect-trailing-slash-handler can end up redirecting to external URL
This requires a specific route configuration that includes a route that can potentially match a path that starts with //
, for example in this minimal setup:
(def app
(ring/ring-handler
(ring/router
[["/ping" {:get (constantly {:status 200, :body "ping"})}]
["/*" {:get (constantly nil)}]]
{:conflicts (fn [c])})
(ring/redirect-trailing-slash-handler {:method :strip})))
A request like the following can end up redirecting to an absolute URL outside the app instead of to the relative path that the slash-handler is intending:
(app {:uri "//metosin.github.io/reitit/" :request-method :get})
; {:status 301, :headers {"Location" "//metosin.github.io/reitit"}, :body ""}
;; NB: Browsers will interpret this as a redirect to https://metosin.github.io/reitit
What happens is the following, taking //foo/
as a (shorter) example:
- The wildcard route matches
//foo/
, but returns nil - The URL ends with a
/
, so the slash-handler will strip it - The slash-handler uses
match-by-path
with the stripped URL//foo
, this matches the wildcard route (again) - The slash-handler returns
Location: //foo
in its response, sending the client off to a strange place.
Of course in the real world you wouldn't have a wildcard route that always returns nil, but one could have e.g. a resource-handler on that route that returns nil for any path that does not match a resource filename.
This behaviour could be fixed by stripping multiple slashes at the start of the path before returning it as Location
in the slash handler.