diff --git a/modules/reitit-core/src/reitit/middleware.cljc b/modules/reitit-core/src/reitit/middleware.cljc index ccf512c6..4d9e6de6 100644 --- a/modules/reitit-core/src/reitit/middleware.cljc +++ b/modules/reitit-core/src/reitit/middleware.cljc @@ -16,6 +16,8 @@ (str "Middleware can't have both :wrap and :compile defined " m) m))) (map->Middleware m)) +(def ^:dynamic *max-compile-depth* 10) + (extend-protocol IntoMiddleware #?(:clj clojure.lang.APersistentVector @@ -41,14 +43,21 @@ (into-middleware (create this) data opts)) Middleware - (into-middleware [{:keys [wrap compile] :as this} data opts] + (into-middleware [{:keys [compile] :as this} data opts] (if-not compile this - (if-let [middeware (into-middleware (compile data opts) data opts)] - (map->Middleware - (merge - (dissoc this :create) - (impl/strip-nils middeware)))))) + (let [compiled (::compiled opts 0) + opts (assoc opts ::compiled (inc compiled))] + (when (>= compiled *max-compile-depth*) + (throw + (ex-info + (str "Too deep middleware compilation - " compiled) + {:this this, :data data, :opts opts}))) + (if-let [middeware (into-middleware (compile data opts) data opts)] + (map->Middleware + (merge + (dissoc this :create) + (impl/strip-nils middeware))))))) nil (into-middleware [_ _ _])) diff --git a/test/cljc/reitit/middleware_test.cljc b/test/cljc/reitit/middleware_test.cljc index c4252436..d8ad86e2 100644 --- a/test/cljc/reitit/middleware_test.cljc +++ b/test/cljc/reitit/middleware_test.cljc @@ -111,6 +111,10 @@ (is (= [:data :value :request] (app :request))) (is (= 4 @calls))))) + (testing "too deeply compiled Middleware fails" + (binding [middleware/*max-compile-depth* 2] + (is (thrown? Exception (->app [[(middleware/create mw3) :value]] identity))))) + (testing "nil unmounts the middleware" (let [app (->app [{:compile (constantly nil)} {:compile (constantly nil)}] identity)]