mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 00:11:11 +00:00
ring/create-resource-handler
This commit is contained in:
parent
acbef8527c
commit
c25da60053
5 changed files with 185 additions and 1 deletions
1
dev-resources/public/hello.json
Normal file
1
dev-resources/public/hello.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{"hello": "file"}
|
||||||
1
dev-resources/public/hello.xml
Normal file
1
dev-resources/public/hello.xml
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<xml><hello>file</hello></xml>
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
(ns reitit.ring
|
(ns reitit.ring
|
||||||
(:require [meta-merge.core :refer [meta-merge]]
|
(:require [meta-merge.core :refer [meta-merge]]
|
||||||
[reitit.middleware :as middleware]
|
[reitit.middleware :as middleware]
|
||||||
|
[reitit.ring.mime :as mime]
|
||||||
[reitit.core :as r]
|
[reitit.core :as r]
|
||||||
[reitit.impl :as impl]))
|
[reitit.impl :as impl]
|
||||||
|
#?(:clj
|
||||||
|
[clojure.java.io :as io])))
|
||||||
|
|
||||||
(def http-methods #{:get :head :post :put :delete :connect :options :trace :patch})
|
(def http-methods #{:get :head :post :put :delete :connect :options :trace :patch})
|
||||||
(defrecord Methods [get head post put delete connect options trace patch])
|
(defrecord Methods [get head post put delete connect options trace patch])
|
||||||
|
|
@ -64,6 +67,48 @@
|
||||||
(respond (error-handler request)))
|
(respond (error-handler request)))
|
||||||
(respond (not-found request)))))))
|
(respond (not-found request)))))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn create-resource-handler
|
||||||
|
"A ring handler for handling classpath resources,
|
||||||
|
configured via options:
|
||||||
|
|
||||||
|
| key | description |
|
||||||
|
| -------------|-------------|
|
||||||
|
| :parameter | optional name of the wildcard parameter, defaults to `:`
|
||||||
|
| :root | optional resource root, defaults to `public`
|
||||||
|
| :mime-types | optional extension->mime-type mapping, defaults to `reitit.ring.mime/default-types`
|
||||||
|
| :path | optional path to mount the handler to. Works only outside of a router
|
||||||
|
"
|
||||||
|
([]
|
||||||
|
(create-resource-handler nil))
|
||||||
|
([{:keys [parameter root mime-types path]
|
||||||
|
:or {parameter (keyword "")
|
||||||
|
root "public"
|
||||||
|
mime-types mime/default-mime-types}}]
|
||||||
|
(let [response (fn [file]
|
||||||
|
{:status 200
|
||||||
|
:body file
|
||||||
|
:headers {"Content-Type" (mime/ext-mime-type (.getName file) mime-types)}})]
|
||||||
|
(if path
|
||||||
|
(let [path-size (count path)]
|
||||||
|
(fn
|
||||||
|
([req]
|
||||||
|
(let [uri (:uri req)]
|
||||||
|
(if (and (>= (count uri) path-size))
|
||||||
|
(some->> (str root (subs uri path-size)) io/resource io/file response))))
|
||||||
|
([req respond _]
|
||||||
|
(let [uri (:uri req)]
|
||||||
|
(if (and (>= (count uri) path-size))
|
||||||
|
(some->> (str root (subs uri path-size)) io/resource io/file response respond))))))
|
||||||
|
(fn
|
||||||
|
([req]
|
||||||
|
(or (some->> req :path-params parameter (str root "/") io/resource io/file response)
|
||||||
|
{:status 404}))
|
||||||
|
([req respond _]
|
||||||
|
(respond
|
||||||
|
(or (some->> req :path-params parameter (str root "/") io/resource io/file response)
|
||||||
|
{:status 404})))))))))
|
||||||
|
|
||||||
(defn ring-handler
|
(defn ring-handler
|
||||||
"Creates a ring-handler out of a ring-router.
|
"Creates a ring-handler out of a ring-router.
|
||||||
Supports both 1 (sync) and 3 (async) arities.
|
Supports both 1 (sync) and 3 (async) arities.
|
||||||
|
|
|
||||||
99
modules/reitit-ring/src/reitit/ring/mime.cljc
Normal file
99
modules/reitit-ring/src/reitit/ring/mime.cljc
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
(ns reitit.ring.mime
|
||||||
|
(:require [clojure.string :as str]))
|
||||||
|
|
||||||
|
(def default-mime-types
|
||||||
|
"A map of file extensions to mime-types."
|
||||||
|
{"7z" "application/x-7z-compressed"
|
||||||
|
"aac" "audio/aac"
|
||||||
|
"ai" "application/postscript"
|
||||||
|
"appcache" "text/cache-manifest"
|
||||||
|
"asc" "text/plain"
|
||||||
|
"atom" "application/atom+xml"
|
||||||
|
"avi" "video/x-msvideo"
|
||||||
|
"bin" "application/octet-stream"
|
||||||
|
"bmp" "image/bmp"
|
||||||
|
"bz2" "application/x-bzip"
|
||||||
|
"class" "application/octet-stream"
|
||||||
|
"cer" "application/pkix-cert"
|
||||||
|
"crl" "application/pkix-crl"
|
||||||
|
"crt" "application/x-x509-ca-cert"
|
||||||
|
"css" "text/css"
|
||||||
|
"csv" "text/csv"
|
||||||
|
"deb" "application/x-deb"
|
||||||
|
"dart" "application/dart"
|
||||||
|
"dll" "application/octet-stream"
|
||||||
|
"dmg" "application/octet-stream"
|
||||||
|
"dms" "application/octet-stream"
|
||||||
|
"doc" "application/msword"
|
||||||
|
"dvi" "application/x-dvi"
|
||||||
|
"edn" "application/edn"
|
||||||
|
"eot" "application/vnd.ms-fontobject"
|
||||||
|
"eps" "application/postscript"
|
||||||
|
"etx" "text/x-setext"
|
||||||
|
"exe" "application/octet-stream"
|
||||||
|
"flv" "video/x-flv"
|
||||||
|
"flac" "audio/flac"
|
||||||
|
"gif" "image/gif"
|
||||||
|
"gz" "application/gzip"
|
||||||
|
"htm" "text/html"
|
||||||
|
"html" "text/html"
|
||||||
|
"ico" "image/x-icon"
|
||||||
|
"iso" "application/x-iso9660-image"
|
||||||
|
"jar" "application/java-archive"
|
||||||
|
"jpe" "image/jpeg"
|
||||||
|
"jpeg" "image/jpeg"
|
||||||
|
"jpg" "image/jpeg"
|
||||||
|
"js" "text/javascript"
|
||||||
|
"json" "application/json"
|
||||||
|
"lha" "application/octet-stream"
|
||||||
|
"lzh" "application/octet-stream"
|
||||||
|
"mov" "video/quicktime"
|
||||||
|
"m4v" "video/mp4"
|
||||||
|
"mp3" "audio/mpeg"
|
||||||
|
"mp4" "video/mp4"
|
||||||
|
"mpe" "video/mpeg"
|
||||||
|
"mpeg" "video/mpeg"
|
||||||
|
"mpg" "video/mpeg"
|
||||||
|
"oga" "audio/ogg"
|
||||||
|
"ogg" "audio/ogg"
|
||||||
|
"ogv" "video/ogg"
|
||||||
|
"pbm" "image/x-portable-bitmap"
|
||||||
|
"pdf" "application/pdf"
|
||||||
|
"pgm" "image/x-portable-graymap"
|
||||||
|
"png" "image/png"
|
||||||
|
"pnm" "image/x-portable-anymap"
|
||||||
|
"ppm" "image/x-portable-pixmap"
|
||||||
|
"ppt" "application/vnd.ms-powerpoint"
|
||||||
|
"ps" "application/postscript"
|
||||||
|
"qt" "video/quicktime"
|
||||||
|
"rar" "application/x-rar-compressed"
|
||||||
|
"ras" "image/x-cmu-raster"
|
||||||
|
"rb" "text/plain"
|
||||||
|
"rd" "text/plain"
|
||||||
|
"rss" "application/rss+xml"
|
||||||
|
"rtf" "application/rtf"
|
||||||
|
"sgm" "text/sgml"
|
||||||
|
"sgml" "text/sgml"
|
||||||
|
"svg" "image/svg+xml"
|
||||||
|
"swf" "application/x-shockwave-flash"
|
||||||
|
"tar" "application/x-tar"
|
||||||
|
"tif" "image/tiff"
|
||||||
|
"tiff" "image/tiff"
|
||||||
|
"ttf" "application/x-font-ttf"
|
||||||
|
"txt" "text/plain"
|
||||||
|
"webm" "video/webm"
|
||||||
|
"wmv" "video/x-ms-wmv"
|
||||||
|
"woff" "application/font-woff"
|
||||||
|
"xbm" "image/x-xbitmap"
|
||||||
|
"xls" "application/vnd.ms-excel"
|
||||||
|
"xml" "text/xml"
|
||||||
|
"xpm" "image/x-xpixmap"
|
||||||
|
"xwd" "image/x-xwindowdump"
|
||||||
|
"zip" "application/zip"})
|
||||||
|
|
||||||
|
(defn file-ext [name]
|
||||||
|
(if-let [i (str/last-index-of name ".")]
|
||||||
|
(subs name (inc i))))
|
||||||
|
|
||||||
|
(defn ext-mime-type [name mime-types]
|
||||||
|
(-> name file-ext mime-types))
|
||||||
|
|
@ -264,3 +264,41 @@
|
||||||
(let [app (create {::middleware/transform #(interleave % (repeat (middleware "debug")))})]
|
(let [app (create {::middleware/transform #(interleave % (repeat (middleware "debug")))})]
|
||||||
(is (= {:status 200, :body [:olipa "debug" :kerran "debug" :avaruus "debug" :ok]}
|
(is (= {:status 200, :body [:olipa "debug" :kerran "debug" :avaruus "debug" :ok]}
|
||||||
(app request)))))))
|
(app request)))))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(deftest resource-handler-test
|
||||||
|
(doseq [[test app] [["inside a router"
|
||||||
|
(ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
[["/ping" (constantly {:status 200, :body "pong"})]
|
||||||
|
["/files/*" (ring/create-resource-handler)]])
|
||||||
|
(ring/create-default-handler))]
|
||||||
|
|
||||||
|
["outside of a router"
|
||||||
|
(ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
["/ping" (constantly {:status 200, :body "pong"})])
|
||||||
|
(ring/routes
|
||||||
|
(ring/create-resource-handler {:path "/files"})
|
||||||
|
(ring/create-default-handler)))]]]
|
||||||
|
|
||||||
|
(testing test
|
||||||
|
(testing "different file-types"
|
||||||
|
(let [response (app {:uri "/files/hello.json", :request-method :get})]
|
||||||
|
(is (= "application/json" (get-in response [:headers "Content-Type"])))
|
||||||
|
(is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
|
||||||
|
(let [response (app {:uri "/files/hello.xml", :request-method :get})]
|
||||||
|
(is (= "text/xml" (get-in response [:headers "Content-Type"])))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
|
||||||
|
|
||||||
|
(testing "not found"
|
||||||
|
(let [response (app {:uri "/files/not-found", :request-method :get})]
|
||||||
|
(is (= 404 (:status response)))))
|
||||||
|
|
||||||
|
(testing "3-arity"
|
||||||
|
(let [result (atom nil)
|
||||||
|
respond (partial reset! result)
|
||||||
|
raise ::not-called]
|
||||||
|
(app {:uri "/files/hello.xml", :request-method :get} respond raise)
|
||||||
|
(is (= "text/xml" (get-in @result [:headers "Content-Type"])))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result))))))))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue