mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 08:21:11 +00:00
use ring for serving resources.
This commit is contained in:
parent
fc0b634865
commit
f8a43f0996
7 changed files with 104 additions and 145 deletions
|
|
@ -25,6 +25,12 @@
|
||||||
* new helper `reitit.ring/router` to compose routes outside of a router.
|
* new helper `reitit.ring/router` to compose routes outside of a router.
|
||||||
* `reitit.ring/create-resource-handler` function to serve static routes. See (docs)[https://metosin.github.io/reitit/ring/static.html].
|
* `reitit.ring/create-resource-handler` function to serve static routes. See (docs)[https://metosin.github.io/reitit/ring/static.html].
|
||||||
|
|
||||||
|
* new dependencies:
|
||||||
|
|
||||||
|
```clj
|
||||||
|
[ring/ring-core "1.6.3"]
|
||||||
|
```
|
||||||
|
|
||||||
### `reitit-swagger`
|
### `reitit-swagger`
|
||||||
|
|
||||||
* New module to produce swagger-docs from routing tree, including `Coercion` definitions. Works with both middleware & interceptors and Schema & Spec. See [docs](https://metosin.github.io/reitit/swagger.html).
|
* New module to produce swagger-docs from routing tree, including `Coercion` definitions. Works with both middleware & interceptors and Schema & Spec. See [docs](https://metosin.github.io/reitit/swagger.html).
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ There are two options to serve the files.
|
||||||
|
|
||||||
This is good option if static files can be from non-conflicting paths, e.g. `"/assets/*"`.
|
This is good option if static files can be from non-conflicting paths, e.g. `"/assets/*"`.
|
||||||
|
|
||||||
|
|
||||||
```clj
|
```clj
|
||||||
(require '[reitit.ring :as ring])
|
(require '[reitit.ring :as ring])
|
||||||
|
|
||||||
|
|
@ -50,13 +49,16 @@ To serve files from conflicting paths, e.g. `"/*"`, one option is to mount them
|
||||||
|
|
||||||
`reitit.ring/create-resource-handler` takes optionally an options map to configure how the files are being served.
|
`reitit.ring/create-resource-handler` takes optionally an options map to configure how the files are being served.
|
||||||
|
|
||||||
| key | description |
|
| key | description |
|
||||||
| -------------|-------------|
|
| -----------------|-------------|
|
||||||
| :parameter | optional name of the wildcard parameter, defaults to unnamed keyword `:`
|
| :parameter | optional name of the wildcard parameter, defaults to unnamed keyword `:`
|
||||||
| :root | optional resource root, defaults to `"public"`
|
| :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 if mounted outside of a router.
|
||||||
| :path | optional path to mount the handler to. Works only if mounted outside of a router.
|
| :loader | optional class loader to resolve the resources
|
||||||
|
| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to `false`
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
|
|
||||||
* support for things like `:cache`, `:last-modified?`, `:index-files` and `:gzip`
|
* support for things like `:cache`, `:last-modified?`, `:index-files` and `:gzip`
|
||||||
|
* support for ClojureScript
|
||||||
|
* serve from file-system
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,5 @@
|
||||||
:plugins [[lein-parent "0.3.2"]]
|
:plugins [[lein-parent "0.3.2"]]
|
||||||
:parent-project {:path "../../project.clj"
|
:parent-project {:path "../../project.clj"
|
||||||
:inherit [:deploy-repositories :managed-dependencies]}
|
:inherit [:deploy-repositories :managed-dependencies]}
|
||||||
:dependencies [[metosin/reitit-core]])
|
:dependencies [[metosin/reitit-core]
|
||||||
|
[ring/ring-core]])
|
||||||
|
|
|
||||||
|
|
@ -1,11 +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
|
#?@(:clj [
|
||||||
[clojure.java.io :as io])))
|
[ring.util.mime-type :as mime-type]
|
||||||
|
[ring.util.response :as response]])))
|
||||||
|
|
||||||
(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])
|
||||||
|
|
@ -71,42 +71,36 @@
|
||||||
(defn create-resource-handler
|
(defn create-resource-handler
|
||||||
"A ring handler for serving classpath resources, configured via options:
|
"A ring handler for serving classpath resources, configured via options:
|
||||||
|
|
||||||
| key | description |
|
| key | description |
|
||||||
| -----------------|-------------|
|
| -----------------|-------------|
|
||||||
| :parameter | optional name of the wildcard parameter, defaults to unnamed keyword `:`
|
| :parameter | optional name of the wildcard parameter, defaults to unnamed keyword `:`
|
||||||
| :root | optional resource root, defaults to `\"public\"`
|
| :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 if mounted outside of a router.
|
| :path | optional path to mount the handler to. Works only if mounted outside of a router.
|
||||||
| :loader | optional class loader to resolve the resources
|
| :loader | optional class loader to resolve the resources
|
||||||
| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to `false`"
|
| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to `false`"
|
||||||
([]
|
([]
|
||||||
(create-resource-handler nil))
|
(create-resource-handler nil))
|
||||||
([{:keys [parameter root mime-types path loader allow-symlinks?]
|
([{:keys [parameter root path loader allow-symlinks?]
|
||||||
:or {parameter (keyword "")
|
:or {parameter (keyword "")
|
||||||
root "public"
|
root "public"}}]
|
||||||
mime-types mime/default-mime-types}}]
|
(let [options {:root root, :loader loader, :allow-symlinks? allow-symlinks?}
|
||||||
(let [response (fn [file]
|
path-size (count path)
|
||||||
{:status 200
|
create (fn [handler]
|
||||||
:body file
|
(fn
|
||||||
:headers {"Content-Type" (mime/ext-mime-type (.getName file) mime-types)}})]
|
([request] (handler request))
|
||||||
(if path
|
([request respond _] (respond (handler request)))))
|
||||||
(let [path-size (count path)
|
response (fn [path]
|
||||||
serve (fn [req]
|
(if-let [response (response/resource-response path options)]
|
||||||
(let [uri (:uri req)]
|
(response/content-type response (mime-type/ext-mime-type path))))
|
||||||
(if (and (>= (count uri) path-size))
|
handler (if path
|
||||||
(some->> (str root (subs uri path-size)) io/resource io/file response))))]
|
(fn [request]
|
||||||
(fn
|
(let [uri (:uri request)]
|
||||||
([req]
|
(if (>= (count uri) path-size)
|
||||||
(serve req))
|
(response (subs uri path-size)))))
|
||||||
([req respond _]
|
(fn [request]
|
||||||
(respond (serve req)))))
|
(let [path (-> request :path-params parameter)]
|
||||||
(let [serve (fn [req]
|
(or (response path) {:status 404}))))]
|
||||||
(or (some->> req :path-params parameter (str root "/") io/resource io/file response)
|
(create handler)))))
|
||||||
{:status 404}))]
|
|
||||||
(fn ([req]
|
|
||||||
(serve req))
|
|
||||||
([req respond _]
|
|
||||||
(respond (serve req))))))))))
|
|
||||||
|
|
||||||
(defn ring-handler
|
(defn ring-handler
|
||||||
"Creates a ring-handler out of a ring-router.
|
"Creates a ring-handler out of a ring-router.
|
||||||
|
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
(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))
|
|
||||||
|
|
@ -4,7 +4,10 @@
|
||||||
[reitit.ring :as ring]
|
[reitit.ring :as ring]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[criterium.core :as cc]
|
[criterium.core :as cc]
|
||||||
[ring.util.mime-type :as mime]))
|
[ring.util.response]
|
||||||
|
[ring.middleware.defaults]
|
||||||
|
[ring.middleware.resource]
|
||||||
|
[ring.util.mime-type]))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; start repl with `lein perf repl`
|
;; start repl with `lein perf repl`
|
||||||
|
|
@ -21,14 +24,14 @@
|
||||||
;; Memory: 16 GB
|
;; Memory: 16 GB
|
||||||
;;
|
;;
|
||||||
|
|
||||||
(def app
|
(def app1
|
||||||
(ring/ring-handler
|
(ring/ring-handler
|
||||||
(ring/router
|
(ring/router
|
||||||
[["/ping" (constantly {:status 200, :body "pong"})]
|
[["/ping" (constantly {:status 200, :body "pong"})]
|
||||||
["/files/*" (ring/create-resource-handler)]])
|
["/files/*" (ring/create-resource-handler)]])
|
||||||
(ring/create-default-handler)))
|
(ring/create-default-handler)))
|
||||||
|
|
||||||
(def app
|
(def app2
|
||||||
(ring/ring-handler
|
(ring/ring-handler
|
||||||
(ring/router
|
(ring/router
|
||||||
["/ping" (constantly {:status 200, :body "pong"})])
|
["/ping" (constantly {:status 200, :body "pong"})])
|
||||||
|
|
@ -36,19 +39,69 @@
|
||||||
(ring/create-resource-handler {:path "/files"})
|
(ring/create-resource-handler {:path "/files"})
|
||||||
(ring/create-default-handler))))
|
(ring/create-default-handler))))
|
||||||
|
|
||||||
|
(def wrap-resource
|
||||||
|
(-> (constantly {:status 200, :body "pong"})
|
||||||
|
(ring.middleware.resource/wrap-resource "public")))
|
||||||
|
|
||||||
|
(def wrap-defaults
|
||||||
|
(-> (constantly {:status 200, :body "pong"})
|
||||||
|
(ring.middleware.defaults/wrap-defaults ring.middleware.defaults/site-defaults)))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(def server (web/run #'app {:port 3000, :dispatch? false, :server {:always-set-keep-alive false}}))
|
(def server (web/run #'app {:port 3000, :dispatch? false, :server {:always-set-keep-alive false}}))
|
||||||
(routing-test))
|
(routing-test))
|
||||||
|
|
||||||
|
(defn bench-resources []
|
||||||
|
|
||||||
|
;; 134µs
|
||||||
|
(cc/quick-bench
|
||||||
|
(ring.util.response/resource-response "hello.json" {:root "public"}))
|
||||||
|
|
||||||
|
;; 144µs
|
||||||
|
(cc/quick-bench
|
||||||
|
(app1 {:request-method :get, :uri "/files/hello.json"}))
|
||||||
|
|
||||||
|
;; 144µs
|
||||||
|
(cc/quick-bench
|
||||||
|
(app2 {:request-method :get, :uri "/files/hello.json"}))
|
||||||
|
|
||||||
|
;; 143µs
|
||||||
|
(cc/quick-bench
|
||||||
|
(wrap-resource {:request-method :get, :uri "/hello.json"}))
|
||||||
|
|
||||||
|
;; 163µs
|
||||||
|
(cc/quick-bench
|
||||||
|
(wrap-defaults {:request-method :get, :uri "/hello.json"})))
|
||||||
|
|
||||||
|
(defn bench-handler []
|
||||||
|
|
||||||
|
;; 140ns
|
||||||
|
(cc/quick-bench
|
||||||
|
(app1 {:request-method :get, :uri "/ping"}))
|
||||||
|
|
||||||
|
;; 134ns
|
||||||
|
(cc/quick-bench
|
||||||
|
(app2 {:request-method :get, :uri "/ping"}))
|
||||||
|
|
||||||
|
;; 108µs
|
||||||
|
(cc/quick-bench
|
||||||
|
(wrap-resource {:request-method :get, :uri "/ping"}))
|
||||||
|
|
||||||
|
;; 146µs
|
||||||
|
(cc/quick-bench
|
||||||
|
(wrap-defaults {:request-method :get, :uri "/ping"})))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
|
(bench-resources)
|
||||||
|
(bench-handler)
|
||||||
|
|
||||||
(let [file (-> "logback.xml" io/resource io/file)
|
(let [file (-> "logback.xml" io/resource io/file)
|
||||||
name (.getName file)]
|
name (.getName file)]
|
||||||
|
|
||||||
;; 639ns
|
;; 639ns
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(mime/ext-mime-type name))
|
(ring.util.mime-type/ext-mime-type name))
|
||||||
|
|
||||||
|
|
||||||
;; 106ns
|
;; 106ns
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(ext-mime-type name))))
|
(reitit.ring.mime/ext-mime-type name reitit.ring.mime/default-mime-types))))
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
[metosin/reitit-swagger "0.1.1-SNAPSHOT"]
|
[metosin/reitit-swagger "0.1.1-SNAPSHOT"]
|
||||||
|
|
||||||
[meta-merge "1.0.0"]
|
[meta-merge "1.0.0"]
|
||||||
|
[ring/ring-core "1.6.3"]
|
||||||
[metosin/spec-tools "0.6.2-SNAPSHOT"]
|
[metosin/spec-tools "0.6.2-SNAPSHOT"]
|
||||||
[metosin/schema-tools "0.10.2-SNAPSHOT"]]
|
[metosin/schema-tools "0.10.2-SNAPSHOT"]]
|
||||||
|
|
||||||
|
|
@ -60,6 +61,7 @@
|
||||||
"-Dclojure.compiler.direct-linking=true"]
|
"-Dclojure.compiler.direct-linking=true"]
|
||||||
:test-paths ["perf-test/clj"]
|
:test-paths ["perf-test/clj"]
|
||||||
:dependencies [[compojure "1.6.1"]
|
:dependencies [[compojure "1.6.1"]
|
||||||
|
[ring/ring-defaults "0.3.1"]
|
||||||
[ikitommi/immutant-web "3.0.0-alpha1"]
|
[ikitommi/immutant-web "3.0.0-alpha1"]
|
||||||
[io.pedestal/pedestal.route "0.5.3"]
|
[io.pedestal/pedestal.route "0.5.3"]
|
||||||
[org.clojure/core.async "0.4.474"]
|
[org.clojure/core.async "0.4.474"]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue