Codebase list comidi-clojure / 159ef0f
(TK-297) Fix wrap-routes Make sure the wrap-routes function only ever modifies the handlers in bidi route trees and never the patterns. Previously it could modify even the patterns (although only less common ones) and thus corrupt the route tree. Michal Růžička 8 years ago
2 changed file(s) with 43 addition(s) and 18 deletion(s). Raw diff Collapse all Expand all
275275 [method pattern bindings body]
276276 `[~pattern {~method (handler-fn* ~bindings ~body)}])
277277
278 (defn route-tree-zip
279 "Returns a zipper for a bidi route tree i.e. for an arbitrarily nested structure of
280 `bidi.schema/RoutePair`s"
281 [root]
282 (zip/zipper
283 (fn [[_ matched]]
284 (or (vector? matched) (map? matched)))
285
286 (fn [[_ matched]]
287 (seq matched))
288
289 (fn [[pattern matched :as node] children]
290 (with-meta
291 [pattern (into (if (vector? matched) [] {}) children)]
292 (meta node)))
293
294 root))
295
278296 (defn wrap-routes*
279297 "Help function, used by compojure-like wrap-routes function to wrap leaf handlers
280298 in the bidi route with the middleware"
281299 [loc middleware]
282 (let [node (zip/node loc)
283 loc (cond
284 (fn? node) (zip/replace loc (middleware node))
285 (map? node) (zip/replace
286 loc
287 (reduce-kv (fn [m k v] (assoc m k (middleware v))) {} node))
288 :else loc)]
289 (if (zip/end? loc)
290 loc
291 (wrap-routes* (zip/next loc) middleware))))
300 (if (zip/end? loc)
301 loc
302 (let [loc (if (zip/branch? loc) ; we only want modify the leaf nodes
303 loc
304 (let [[pattern matched] (zip/node loc)]
305 (if (fn? matched)
306 (zip/replace loc [pattern (middleware matched)])
307 loc)))]
308 (recur (zip/next loc) middleware))))
292309
293310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
294311 ;;;; Public - core functions
327344 [routes :- bidi-schema/RoutePair
328345 middleware :- (schema/pred fn?)]
329346 (-> routes
330 zip/vector-zip
347 route-tree-zip
331348 (wrap-routes* middleware)
332349 zip/root))
333350
22 [puppetlabs.comidi :as comidi :refer :all]
33 [schema.test :as schema-test]
44 [schema.core :as schema]
5 [clojure.zip :as zip]))
5 [clojure.zip :as zip]
6 [bidi.bidi :as bidi]))
67
78 (use-fixtures :once schema-test/validate-schemas)
89
358359 dd-route (DELETE "/dd" request "dd!")
359360 ee-route (GET "/ee" request "ee!")
360361 ff-route (ANY "/ff" request "ff!")
362 gh-route (ANY (bidi/alts "/gg" "/hh") request "gg-or-hh!")
361363 left-routes (context "/left" aa-route bb-route)
362364 middle-routes (context "/middle" cc-route dd-route)
363365 right-routes (context "/right" ee-route ff-route)
364 handler (-> (routes left-routes middle-routes right-routes) routes->handler)]
366 alternate-routes ["/alts" [gh-route]]
367 handler (-> (routes left-routes middle-routes right-routes alternate-routes) routes->handler)]
365368 (testing "Routes without middleware applied"
366369 (is (= (:body (handler {:uri "/left/aa" :request-method :get})) "aa!"))
367370 (is (= (:body (handler {:uri "/left/bb" :request-method :post})) "bb!"))
368371 (is (= (:body (handler {:uri "/middle/cc" :request-method :get})) "cc!"))
369372 (is (= (:body (handler {:uri "/middle/dd" :request-method :delete})) "dd!"))
370373 (is (= (:body (handler {:uri "/right/ee" :request-method :get})) "ee!"))
371 (is (= (:body (handler {:uri "/right/ff" :request-method :delete})) "ff!")))
374 (is (= (:body (handler {:uri "/right/ff" :request-method :delete})) "ff!"))
375 (is (= (:body (handler {:uri "/alts/gg" :request-method :put})) "gg-or-hh!"))
376 (is (= (:body (handler {:uri "/alts/hh" :request-method :post})) "gg-or-hh!"))
377 (is (= (:body (handler {:uri "/alts/ii" :request-method :post})) nil)))
372378 (testing "Routes but now with middleware applied"
373379 (let [wrapped-bb-route (-> bb-route (wrap-routes bb-wrapper-middleware))
374380 left-routes (-> (context "/left" aa-route wrapped-bb-route)
375381 (wrap-routes inner-middleware)
376382 (wrap-routes outer-middleware))
377 middle-routes (context "/middle" cc-route dd-route)
378 right-routes (-> (context "/right" ee-route ff-route) (wrap-routes outer-middleware))
379 handler (-> (routes left-routes middle-routes right-routes) routes->handler)]
383 right-routes (-> right-routes (wrap-routes outer-middleware))
384 alternate-routes (-> alternate-routes (wrap-routes inner-middleware) (wrap-routes outer-middleware))
385 handler (-> (routes left-routes middle-routes right-routes alternate-routes) routes->handler)]
380386 (is (= (:body (handler {:uri "/left/aa" :request-method :get})) "outer-inner-aa!"))
381387 (is (= (:body (handler {:uri "/left/bb" :request-method :post})) "outer-inner-bb-wrapper-bb!"))
382388 (is (= (:body (handler {:uri "/middle/cc" :request-method :get})) "cc!"))
383389 (is (= (:body (handler {:uri "/middle/dd" :request-method :delete})) "dd!"))
384390 (is (= (:body (handler {:uri "/right/ee" :request-method :get})) "outer-ee!"))
385 (is (= (:body (handler {:uri "/right/ff" :request-method :delete})) "outer-ff!"))))))
391 (is (= (:body (handler {:uri "/right/ff" :request-method :delete})) "outer-ff!"))
392 (is (= (:body (handler {:uri "/alts/gg" :request-method :delete})) "outer-inner-gg-or-hh!"))
393 (is (= (:body (handler {:uri "/alts/hh" :request-method :delete})) "outer-inner-gg-or-hh!"))))))
386394
387395 (deftest destructuring-test
388396 (testing "Compojure-style destructuring works as expected"