From 7ce01f890cb453dda1c3029cf29fb251f0cc4f4e Mon Sep 17 00:00:00 2001 From: James Reeves Date: Thu, 31 Aug 2023 14:38:33 +0100 Subject: [PATCH] Add spaces after semicolons in Set-Cookie header Fixes #486. --- ring-core/src/ring/middleware/cookies.clj | 10 +++++----- ring-core/test/ring/middleware/test/cookies.clj | 14 +++++++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/ring-core/src/ring/middleware/cookies.clj b/ring-core/src/ring/middleware/cookies.clj index 3bb8f5c8..860f5053 100644 --- a/ring-core/src/ring/middleware/cookies.clj +++ b/ring-core/src/ring/middleware/cookies.clj @@ -106,12 +106,12 @@ (for [[key value] attrs] (let [attr (name (set-cookie-attrs key))] (cond - (satisfies? CookieInterval value) (str ";" attr "=" (->seconds value)) - (satisfies? CookieDateTime value) (str ";" attr "=" (rfc822-format value)) - (true? value) (str ";" attr) + (satisfies? CookieInterval value) (str "; " attr "=" (->seconds value)) + (satisfies? CookieDateTime value) (str "; " attr "=" (rfc822-format value)) + (true? value) (str "; " attr) (false? value) "" - (= :same-site key) (str ";" attr "=" (same-site-values value)) - :else (str ";" attr "=" value))))) + (= :same-site key) (str "; " attr "=" (same-site-values value)) + :else (str "; " attr "=" value))))) (defn- write-cookies [cookies encoder] (for [[key value] cookies] diff --git a/ring-core/test/ring/middleware/test/cookies.clj b/ring-core/test/ring/middleware/test/cookies.clj index 58a1553f..f19a3afb 100644 --- a/ring-core/test/ring/middleware/test/cookies.clj +++ b/ring-core/test/ring/middleware/test/cookies.clj @@ -47,7 +47,7 @@ (:headers resp))))) (defn- split-set-cookie [headers] - (letfn [(split-header [v] (set (mapcat #(str/split % #";") v)))] + (letfn [(split-header [v] (set (mapcat #(str/split % #"; ?") v)))] (update-in headers ["Set-Cookie"] split-header))) (deftest wrap-cookies-set-extra-attrs @@ -169,6 +169,18 @@ 0 0 0 0 (ZoneId/of "UTC"))) +(deftest wrap-cookies-spaces-after-semicolons-test + (let [cookies {"a" {:value "b" + :path "/", :secure true, :same-site :lax + :expires (zoned-date-time 2015 12 31) + :max-age (Duration/between (zoned-date-time 2012) + (zoned-date-time 2015))}} + handler (constantly {:cookies cookies}) + resp ((wrap-cookies handler) {}) + header (first (get-in resp [:headers "Set-Cookie"]))] + (is (re-matches #"([^;]+; )+([^;]+)" header) + "spaces after semicolons in Set-Cookie"))) + (deftest wrap-cookies-accepts-max-age-from-java-time (let [cookies {"a" {:value "b", :path "/", :secure true, :http-only true,