Make index-redirect? default to false, add dir to dir/ redirect

- When canonicalize-uris? is true, redirect from dir to dir/ if index
  file exists within the directory
- Add more tests
This commit is contained in:
Juho Teperi 2025-03-27 14:47:14 +02:00
parent 12afe1dcaa
commit e50bfa835c
5 changed files with 56 additions and 29 deletions

View file

@ -231,7 +231,7 @@
:or {parameter (keyword "") :or {parameter (keyword "")
root "public" root "public"
index-files ["index.html"] index-files ["index.html"]
index-redirect? true index-redirect? false
canonicalize-uris? true canonicalize-uris? true
paths (constantly nil)}}] paths (constantly nil)}}]
(let [options {:root root (let [options {:root root
@ -259,8 +259,14 @@
(loop [[file & files] index-files] (loop [[file & files] index-files]
(if file (if file
(if-let [resp (response (join-paths path file))] (if-let [resp (response (join-paths path file))]
(if index-redirect? (cond
index-redirect?
(response/redirect (join-paths uri file)) (response/redirect (join-paths uri file))
(not (str/ends-with? uri "/"))
(response/redirect (str uri "/"))
:else
resp) resp)
(recur files))))))) (recur files)))))))
handler (if path handler (if path
@ -287,8 +293,8 @@
| :path | path to mount the handler to. Required when mounted outside of a router, does not work inside a router. | :path | path to mount the handler to. Required when mounted outside of a router, does not work inside a router.
| :loader | optional class loader to resolve the resources | :loader | optional class loader to resolve the resources
| :index-files | optional vector of index-files to look in a resource directory, defaults to `[\"index.html\"]` | :index-files | optional vector of index-files to look in a resource directory, defaults to `[\"index.html\"]`
| :index-redirect? | optional boolean: if true (default), redirect to index file, if false serve it directly | :index-redirect? | optional boolean: if true, redirect to index file, if false serve it directly
| :canonicalize-uris? | optional boolean: if true (default), try to serve index files for non directory paths (paths that end with slash) | :canonicalize-uris? | optional boolean: if true (default), if path points to a folder with an index file, add a trailing slash (redirect) if it is missing.
| :not-found-handler | optional handler function to use if the requested resource is missing (404 Not Found)" | :not-found-handler | optional handler function to use if the requested resource is missing (404 Not Found)"
([] ([]
(create-resource-handler nil)) (create-resource-handler nil))
@ -306,8 +312,8 @@
| :path | path to mount the handler to. Required when mounted outside of a router, does not work inside a router. | :path | path to mount the handler to. Required when mounted outside of a router, does not work inside a router.
| :loader | optional class loader to resolve the resources | :loader | optional class loader to resolve the resources
| :index-files | optional vector of index-files to look in a resource directory, defaults to `[\"index.html\"]` | :index-files | optional vector of index-files to look in a resource directory, defaults to `[\"index.html\"]`
| :index-redirect? | optional boolean: if true (default), redirect to index file, if false serve it directly | :index-redirect? | optional boolean: if true, redirect to index file, if false serve it directly
| :canonicalize-uris? | optional boolean: if true (default), try to serve index files for non directory paths (paths that end with slash) | :canonicalize-uris? | optional boolean: if true (default), if path points to a folder with an index file, add a trailing slash (redirect) if it is missing.
| :not-found-handler | optional handler function to use if the requested resource is missing (404 Not Found)" | :not-found-handler | optional handler function to use if the requested resource is missing (404 Not Found)"
([] ([]
(create-file-handler nil)) (create-file-handler nil))

View file

@ -386,9 +386,9 @@
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= (redirect "/docs/index.html") response))) (is (= (redirect "/docs/") response)))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= (redirect "/docs/index.html") response)))) (is (= 200 (:status response)))))
(testing "not found" (testing "not found"
(let [response (app (request "/not-found"))] (let [response (app (request "/not-found"))]
@ -424,9 +424,9 @@
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= (redirect "/docs/index.html") response))) (is (= (redirect "/docs/") response)))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= (redirect "/docs/index.html") response)))) (is (= 200 (:status response)))))
(testing "not found" (testing "not found"
(let [response (app (request "/not-found"))] (let [response (app (request "/not-found"))]
@ -463,9 +463,9 @@
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= (redirect "/docs/index.html") response))) (is (= (redirect "/docs/") response)))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= (redirect "/docs/index.html") response)))) (is (= 200 (:status response)))))
(testing "not found" (testing "not found"
(let [response (app (request "/not-found"))] (let [response (app (request "/not-found"))]
@ -502,9 +502,9 @@
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= (redirect "/docs/index.html") response))) (is (= (redirect "/docs/") response)))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= (redirect "/docs/index.html") response)))) (is (= 200 (:status response)))))
(testing "not found" (testing "not found"
(let [response (app (request "/not-found"))] (let [response (app (request "/not-found"))]

View file

@ -337,7 +337,7 @@
{:path "/" {:path "/"
:url "/openapi.json" :url "/openapi.json"
:config {:jsonEditor true}})] :config {:jsonEditor true}})]
(is (= 302 (:status (app {:request-method :get, :uri "/"})))) (is (= 200 (:status (app {:request-method :get, :uri "/"}))))
(is (= 200 (:status (app {:request-method :get, :uri "/index.html"})))) (is (= 200 (:status (app {:request-method :get, :uri "/index.html"}))))
(is (= {:jsonEditor true, :url "/openapi.json"} (is (= {:jsonEditor true, :url "/openapi.json"}
(->> {:request-method :get, :uri "/config.json"} (->> {:request-method :get, :uri "/config.json"}

View file

@ -526,9 +526,9 @@
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= (redirect "/docs/index.html") response))) (is (= (redirect "/docs/") response)))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= (redirect "/docs/index.html") response)))) (is (= 200 (:status response)))))
(testing "not found" (testing "not found"
(let [response (app (request "/not-found"))] (let [response (app (request "/not-found"))]
@ -567,9 +567,9 @@
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= (redirect "/docs/index.html") response))) (is (= (redirect "/docs/") response)))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= (redirect "/docs/index.html") response)))) (is (= 200 (:status response)))))
(testing "not found" (testing "not found"
(let [response (app (request "/not-found"))] (let [response (app (request "/not-found"))]
@ -609,9 +609,9 @@
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= (redirect "/docs/index.html") response))) (is (= (redirect "/docs/") response)))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= (redirect "/docs/index.html") response)))) (is (= 200 (:status response)))))
(testing "not found" (testing "not found"
(let [response (app (request "/not-found"))] (let [response (app (request "/not-found"))]
@ -652,9 +652,9 @@
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= (redirect "/docs/index.html") response))) (is (= (redirect "/docs/") response)))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= (redirect "/docs/index.html") response)))) (is (= 200 (:status response)))))
(testing "not found" (testing "not found"
(let [response (app {:uri "/not-found" :request-method :get})] (let [response (app {:uri "/not-found" :request-method :get})]
@ -688,13 +688,13 @@
(testing "without index-redirect" (testing "without index-redirect"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
["/*" (create {:index-redirect? false})]) ["/*" (create {:canonicalize-uris? false
:index-redirect? false})])
(ring/create-default-handler))] (ring/create-default-handler))]
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= 200 (:status response))) (is (= 404 (:status response))))
(is (= "<h1>hello</h1>\n" (slurp (:body response)))))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= 200 (:status response))) (is (= 200 (:status response)))
(is (= "<h1>hello</h1>\n" (slurp (:body response)))))))) (is (= "<h1>hello</h1>\n" (slurp (:body response))))))))
@ -705,6 +705,24 @@
["/*" (create {:canonicalize-uris? true})]) ["/*" (create {:canonicalize-uris? true})])
(ring/create-default-handler))] (ring/create-default-handler))]
(testing "index-files"
(let [response (app (request "/docs"))]
(is (= (redirect "/docs/") response)))
(testing "not found if dir doesn't exist"
(let [response (app (request "/foobar"))]
(is (= 404 (:status response)))))
(let [response (app (request "/docs/"))]
(is (= 200 (:status response))))
(let [response (app (request "/docs/index.html"))]
(is (= 200 (:status response)))))))
(testing "with canonicalize-uris and index-redirect"
(let [app (ring/ring-handler
(ring/router
["/*" (create {:canonicalize-uris? true
:index-redirect? true})])
(ring/create-default-handler))]
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= (redirect "/docs/index.html") response))) (is (= (redirect "/docs/index.html") response)))
@ -714,14 +732,17 @@
(testing "without canonicalize-uris" (testing "without canonicalize-uris"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
["/*" (create {:canonicalize-uris? false})]) ["/*" (create {:canonicalize-uris? false
:index-redirect? true})])
(ring/create-default-handler))] (ring/create-default-handler))]
(testing "index-files" (testing "index-files"
(let [response (app (request "/docs"))] (let [response (app (request "/docs"))]
(is (= 404 (:status response)))) (is (= 404 (:status response))))
(let [response (app (request "/docs/"))] (let [response (app (request "/docs/"))]
(is (= (redirect "/docs/index.html") response))))))))))) (is (= (redirect "/docs/index.html") response)))
(let [response (app (request "/foobar"))]
(is (= 404 (:status response))))))))))))
#?(:clj #?(:clj
(deftest file-resource-handler-not-found-test (deftest file-resource-handler-not-found-test

View file

@ -392,7 +392,7 @@
(let [app (swagger-ui/create-swagger-ui-handler (let [app (swagger-ui/create-swagger-ui-handler
{:path "/" {:path "/"
:config {:jsonEditor true}})] :config {:jsonEditor true}})]
(is (= 302 (:status (app {:request-method :get, :uri "/"})))) (is (= 200 (:status (app {:request-method :get, :uri "/"}))))
(is (= 200 (:status (app {:request-method :get, :uri "/index.html"})))) (is (= 200 (:status (app {:request-method :get, :uri "/index.html"}))))
(is (= {:jsonEditor true, :url "/swagger.json"} (is (= {:jsonEditor true, :url "/swagger.json"}
(->> {:request-method :get, :uri "/config.json"} (->> {:request-method :get, :uri "/config.json"}