From 014fedc97126f173fb45929c0c17957e8a45d212 Mon Sep 17 00:00:00 2001 From: Liam Chen Date: Wed, 27 Apr 2022 14:15:01 -0400 Subject: [PATCH 1/2] Add a full-route key to the request map This provides access to the full route that contains the common prefix. The full-route info is added to the ':compojure/full-route' key in the request map. Co-authored-by: Liam Chen Co-authored-by: Claire Alvis --- src/compojure/core.clj | 44 ++++++++++++++++++++++++++---------- test/compojure/core_test.clj | 30 ++++++++++++++++++++---- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/compojure/core.clj b/src/compojure/core.clj index 32b25de9..3c8e871e 100644 --- a/src/compojure/core.clj +++ b/src/compojure/core.clj @@ -134,9 +134,17 @@ (defn- wrap-route-info [handler route-info] (fn ([request] - (handler (assoc request :compojure/route route-info))) + (let [full-route (str (:compojure/context request) (second route-info))] + (handler (assoc request + :compojure/route route-info + :compojure/full-route full-route)))) ([request respond raise] - (handler (assoc request :compojure/route route-info) respond raise)))) + (let [full-route (str (:compojure/context request) (second route-info))] + (handler (assoc request + :compojure/route route-info + :compojure/full-route full-route) + respond + raise))))) (defn- wrap-route-matches [handler method path] (fn @@ -257,27 +265,39 @@ path (:path-info request uri) context (or (:context request) "") subpath (:__path-info params) - params (dissoc params :__path-info)] + params (dissoc params :__path-info) + context-route (:context-route (meta route))] (-> request (assoc-route-params (decode-route-params params)) (assoc :path-info (if (= subpath "") "/" subpath) - :context (remove-suffix uri subpath)))))) + :context (remove-suffix uri subpath)) + (update :compojure/context (fn [ctx] (str ctx context-route))))))) (defn- context-route [route] (let [re-context {:__path-info #"|/.*"}] (cond (string? route) - (clout/route-compile (str route ":__path-info") re-context) + (with-meta (clout/route-compile (str route ":__path-info") re-context) + {:context-route route}) (and (vector? route) (literal? route)) - (clout/route-compile - (str (first route) ":__path-info") - (merge (apply hash-map (rest route)) re-context)) + (with-meta (clout/route-compile + (str (first route) ":__path-info") + (merge (apply hash-map (rest route)) re-context)) + {:context-route (first route)}) (vector? route) - `(clout/route-compile - (str ~(first route) ":__path-info") - ~(merge (apply hash-map (rest route)) re-context)) + `(let [route# ~(first route)] + (with-meta + (clout/route-compile + (str route# ":__path-info") + ~(merge (apply hash-map (rest route)) re-context)) + {:context-route route#})) :else - `(clout/route-compile (str ~route ":__path-info") ~re-context)))) + `(let [route# ~route] + (with-meta + (clout/route-compile (str route# ":__path-info") ~re-context) + (if (string? route#) + {:context-route route#} + {})))))) (defn ^:no-doc make-context [route make-handler] (letfn [(handler diff --git a/test/compojure/core_test.clj b/test/compojure/core_test.clj index f5430801..8da4a927 100644 --- a/test/compojure/core_test.clj +++ b/test/compojure/core_test.clj @@ -38,7 +38,7 @@ (assoc :params {:y "bar"}))] ((GET "/:x" [x :as r] (is (= x "foo")) - (is (= (dissoc r :params :route-params :compojure/route) + (is (= (dissoc r :params :route-params :compojure/route :compojure/full-route) (dissoc req :params))) nil) req))) @@ -212,7 +212,7 @@ (let [handler (GET "/ip/:ip" [ip] ip) cxt-handler (context "/ip/:ip" [ip] (GET "/" [] ip)) in-cxt-handler (context "/ip" [] (GET "/:ip" [ip] ip)) - request (mock/request :get "/ip/0%3A0%3A0%3A0%3A0%3A0%3A0%3A1%250") ] + request (mock/request :get "/ip/0%3A0%3A0%3A0%3A0%3A0%3A0%3A1%250")] (is (= (-> request handler :body) "0:0:0:0:0:0:0:1%0")) (is (= (-> request cxt-handler :body) "0:0:0:0:0:0:0:1%0")) (is (= (-> request in-cxt-handler :body) "0:0:0:0:0:0:0:1%0")))) @@ -221,7 +221,7 @@ (let [handler (GET "/emote/:emote" [emote] emote) cxt-handler (context "/emote/:emote" [emote] (GET "/" [] emote)) in-cxt-handler (context "/emote" [] (GET "/:emote" [emote] emote)) - request (mock/request :get "/emote/%5C%3F%2F") ] + request (mock/request :get "/emote/%5C%3F%2F")] (is (= (-> request handler :body) "\\?/")) (is (= (-> request cxt-handler :body) "\\?/")) (is (= (-> request in-cxt-handler :body) "\\?/")))) @@ -323,7 +323,29 @@ request (route (mock/request :post "/foo/1" {}))] (testing "ANY request has matched route information" (is (= (request :compojure/route) - [:any "/foo/:id"]))))) + [:any "/foo/:id"])) + (is (= (request :compojure/full-route) + "/foo/:id")))) + + (let [route (context "/foo/:foo-id" [_] (GET "/bar/:bar-id" req req)) + request (route (mock/request :get "/foo/1/bar/2"))] + (testing "request has matched route information with path prefix" + (is (= (request :compojure/route) + [:get "/bar/:bar-id"])) + (is (= (request :compojure/context) + "/foo/:foo-id")) + (is (= (request :compojure/full-route) + "/foo/:foo-id/bar/:bar-id")))) + + (let [route (context "/foo/:foo-id" [_] + (context "/bar/:bar-id" [_] + (GET "/baz/:baz-id" req req))) + request (route (mock/request :get "/foo/1/bar/2/baz/3"))] + (testing "request has matched route information with multiple path prefix" + (is (= (request :compojure/context) + "/foo/:foo-id/bar/:bar-id")) + (is (= (request :compojure/full-route) + "/foo/:foo-id/bar/:bar-id/baz/:baz-id"))))) (deftest route-async-test (testing "single route" From 7f0a1f69d4f67e54a16829b6beef5661c4017e8f Mon Sep 17 00:00:00 2001 From: Liam Chen Date: Mon, 2 May 2022 16:28:39 -0400 Subject: [PATCH 2/2] pass the path through to the context-request function This approach is simpler, pass the path down, rather than attaching it to the meta. --- src/compojure/core.clj | 48 ++++++++++++++---------------------- test/compojure/core_test.clj | 4 +-- 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/src/compojure/core.clj b/src/compojure/core.clj index 3c8e871e..304cfb86 100644 --- a/src/compojure/core.clj +++ b/src/compojure/core.clj @@ -134,12 +134,12 @@ (defn- wrap-route-info [handler route-info] (fn ([request] - (let [full-route (str (:compojure/context request) (second route-info))] + (let [full-route (str (:compojure/context-path request) (second route-info))] (handler (assoc request :compojure/route route-info :compojure/full-route full-route)))) ([request respond raise] - (let [full-route (str (:compojure/context request) (second route-info))] + (let [full-route (str (:compojure/context-path request) (second route-info))] (handler (assoc request :compojure/route route-info :compojure/full-route full-route) @@ -259,47 +259,34 @@ (defn- remove-suffix [path suffix] (subs path 0 (- (count path) (count suffix)))) -(defn- context-request [request route] +(defn- context-request [request route context-path] (if-let [params (clout/route-matches route request)] (let [uri (:uri request) - path (:path-info request uri) - context (or (:context request) "") subpath (:__path-info params) - params (dissoc params :__path-info) - context-route (:context-route (meta route))] + params (dissoc params :__path-info)] (-> request (assoc-route-params (decode-route-params params)) (assoc :path-info (if (= subpath "") "/" subpath) :context (remove-suffix uri subpath)) - (update :compojure/context (fn [ctx] (str ctx context-route))))))) + (update :compojure/context-path (fn [ctx] (str ctx context-path))))))) (defn- context-route [route] (let [re-context {:__path-info #"|/.*"}] (cond (string? route) - (with-meta (clout/route-compile (str route ":__path-info") re-context) - {:context-route route}) + (clout/route-compile (str route ":__path-info") re-context) (and (vector? route) (literal? route)) - (with-meta (clout/route-compile - (str (first route) ":__path-info") - (merge (apply hash-map (rest route)) re-context)) - {:context-route (first route)}) + (clout/route-compile + (str (first route) ":__path-info") + (merge (apply hash-map (rest route)) re-context)) (vector? route) - `(let [route# ~(first route)] - (with-meta - (clout/route-compile - (str route# ":__path-info") - ~(merge (apply hash-map (rest route)) re-context)) - {:context-route route#})) + `(clout/route-compile + (str ~(first route) ":__path-info") + ~(merge (apply hash-map (rest route)) re-context)) :else - `(let [route# ~route] - (with-meta - (clout/route-compile (str route# ":__path-info") ~re-context) - (if (string? route#) - {:context-route route#} - {})))))) - -(defn ^:no-doc make-context [route make-handler] + `(clout/route-compile (str ~route ":__path-info") ~re-context)))) + +(defn ^:no-doc make-context [route path make-handler] (letfn [(handler ([request] (when-let [context-handler (make-handler request)] @@ -312,10 +299,10 @@ handler (fn ([request] - (if-let [request (context-request request route)] + (if-let [request (context-request request route path)] (handler request))) ([request respond raise] - (if-let [request (context-request request route)] + (if-let [request (context-request request route path)] (handler request respond raise) (respond nil))))))) @@ -331,6 +318,7 @@ [path args & routes] `(make-context ~(context-route path) + ~path (fn [request#] (let-request [~args request#] (routes ~@routes))))) diff --git a/test/compojure/core_test.clj b/test/compojure/core_test.clj index 8da4a927..cf35e703 100644 --- a/test/compojure/core_test.clj +++ b/test/compojure/core_test.clj @@ -332,7 +332,7 @@ (testing "request has matched route information with path prefix" (is (= (request :compojure/route) [:get "/bar/:bar-id"])) - (is (= (request :compojure/context) + (is (= (request :compojure/context-path) "/foo/:foo-id")) (is (= (request :compojure/full-route) "/foo/:foo-id/bar/:bar-id")))) @@ -342,7 +342,7 @@ (GET "/baz/:baz-id" req req))) request (route (mock/request :get "/foo/1/bar/2/baz/3"))] (testing "request has matched route information with multiple path prefix" - (is (= (request :compojure/context) + (is (= (request :compojure/context-path) "/foo/:foo-id/bar/:bar-id")) (is (= (request :compojure/full-route) "/foo/:foo-id/bar/:bar-id/baz/:baz-id")))))