From 583aac1090a709b92869a22d17c5f648bf132c67 Mon Sep 17 00:00:00 2001 From: jonathannewman Date: Thu, 1 Feb 2024 16:08:35 -0800 Subject: [PATCH 1/2] (maint) add support for multiple Set-Cookie headers The design of the client does not allow multiple entries for the same header name, as headers are returned in a map, rather than an array of them. As a result, headers like "Set-Cookie" would only return the last one seen if they were encountered. This alters the behavior to concatenate any of the "Set-Cookie" entries together, separated by a newline character. This seems to be a fairly common convention for clients that use headers with maps. Tests were updated to include multiple cookies, and demonstrate the behavior. --- CHANGELOG.md | 3 +++ .../http/client/impl/JavaClient.java | 18 +++++++++++++++++- .../http/client/sync_plaintext_test.clj | 4 +++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 136cb3b..5ecb86a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Unreleased +# 2.1.2 +* add support for multiple `Set-Cookie` headers in a response separated by newlines. + # 2.1.1 * [PE-34843](https://tickets.puppetlabs.com/browse/PE-34843) Properly reuse connections when using a client certificate * Update to clj-parent 5.2.11 diff --git a/src/java/com/puppetlabs/http/client/impl/JavaClient.java b/src/java/com/puppetlabs/http/client/impl/JavaClient.java index 890717f..839393b 100644 --- a/src/java/com/puppetlabs/http/client/impl/JavaClient.java +++ b/src/java/com/puppetlabs/http/client/impl/JavaClient.java @@ -295,7 +295,23 @@ private static void completeResponse(ResponseDeliveryDelegate responseDeliveryDe try { Map headers = new HashMap<>(); for (Header h : httpResponse.getAllHeaders()) { - headers.put(h.getName().toLowerCase(), h.getValue()); + String headerName = h.getName().toLowerCase(); + // the http specs allow for multiple headers with the same name, + // but unfortunately since headers are stored in a map, this isn't + // possible without breaking changes. This adds special casing for the + // Set-Cookie header, to add entries separated by newlines. + if (headerName.equals("set-cookie")) { + String headerValue = headers.get("set-cookie"); + if (headerValue != null) { + headers.put(headerName, headerValue + "\n" + h.getValue()); + } + else + { + headers.put(headerName, h.getValue()); + } + } else { + headers.put(headerName.toLowerCase(), h.getValue()); + } } String origContentEncoding = headers.get("content-encoding"); if (requestOptions.getDecompressBody()) { diff --git a/test/puppetlabs/http/client/sync_plaintext_test.clj b/test/puppetlabs/http/client/sync_plaintext_test.clj index 1572a55..278fdca 100644 --- a/test/puppetlabs/http/client/sync_plaintext_test.clj +++ b/test/puppetlabs/http/client/sync_plaintext_test.clj @@ -29,7 +29,8 @@ [_] {:status 200 :body "cookie has been set" - :cookies {"session_id" {:value "session-id-hash"}}}) + :cookies {"session_id" {:value "session-id-hash"} + "someothercookie" {:value "somevalue" :path "/" :secure true}}}) (defn check-cookie-handler [req] @@ -272,6 +273,7 @@ (let [client (Sync/createClient (ClientOptions.))] (testing "Set a cookie using Java API" (let [response (.get client (RequestOptions. "http://localhost:10000/cookietest"))] + (is (= "session_id=session-id-hash\nsomeothercookie=somevalue;Path=/;Secure" (.get (.getHeaders response) "set-cookie"))) (is (= 200 (.getStatus response))))) (testing "Check if cookie still exists" (let [response (.get client (RequestOptions. "http://localhost:10000/cookiecheck"))] From bab65db982ece3a2320ae8988f04931cac20bd4d Mon Sep 17 00:00:00 2001 From: jonathannewman Date: Thu, 1 Feb 2024 16:23:55 -0800 Subject: [PATCH 2/2] (maint) remove use of composite profiles in project.clj In leiningen 2.11.0, composite profiles became a warning. This removes the use of them in favor of explicit profiles to remove the warning. --- CHANGELOG.md | 1 + project.clj | 44 ++++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ecb86a..fb3090a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ # 2.1.2 * add support for multiple `Set-Cookie` headers in a response separated by newlines. +* update project.clj to remove composite profiles that include maps, it is deprecated in lein 2.11.0 # 2.1.1 * [PE-34843](https://tickets.puppetlabs.com/browse/PE-34843) Properly reuse connections when using a client certificate diff --git a/project.clj b/project.clj index 0c046f8..40cae0e 100644 --- a/project.clj +++ b/project.clj @@ -5,7 +5,7 @@ :min-lein-version "2.9.1" - :parent-project {:coords [puppetlabs/clj-parent "5.3.8"] + :parent-project {:coords [puppetlabs/clj-parent "5.6.7"] :inherit [:managed-dependencies]} ;; Abort when version ranges or version conflicts are detected in @@ -44,27 +44,27 @@ [puppetlabs/ring-middleware]] :resource-paths ["dev-resources"] :jvm-opts ["-Djava.util.logging.config.file=dev-resources/logging.properties"]} - :dev [:defaults - {:dependencies [[org.bouncycastle/bcpkix-jdk18on]]}] - :fips [:defaults - {:dependencies [[org.bouncycastle/bcpkix-fips] - [org.bouncycastle/bc-fips] - [org.bouncycastle/bctls-fips]] - ;; this only ensures that we run with the proper profiles - ;; during testing. This JVM opt will be set in the puppet module - ;; that sets up the JVM classpaths during installation. - :jvm-opts ~(let [version (System/getProperty "java.version") - [major minor _] (clojure.string/split version #"\.") - unsupported-ex (ex-info "Unsupported major Java version. Expects 8 or 11." - {:major major - :minor minor})] - (condp = (java.lang.Integer/parseInt major) - 1 (if (= 8 (java.lang.Integer/parseInt minor)) - ["-Djava.security.properties==dev-resources/jdk8-fips-security"] - (throw unsupported-ex)) - 11 ["-Djava.security.properties==dev-resources/jdk11-fips-security"] - 17 ["-Djava.security.properties==dev-resources/jdk17-fips-security"] - (throw unsupported-ex)))}] + :dev-deps {:dependencies [[org.bouncycastle/bcpkix-jdk18on]]} + :dev [:defaults :dev-deps] + :fips-deps {:dependencies [[org.bouncycastle/bcpkix-fips] + [org.bouncycastle/bc-fips] + [org.bouncycastle/bctls-fips]] + ;; this only ensures that we run with the proper profiles + ;; during testing. This JVM opt will be set in the puppet module + ;; that sets up the JVM classpaths during installation. + :jvm-opts ~(let [version (System/getProperty "java.version") + [major minor _] (clojure.string/split version #"\.") + unsupported-ex (ex-info "Unsupported major Java version. Expects 8 or 11." + {:major major + :minor minor})] + (condp = (java.lang.Integer/parseInt major) + 1 (if (= 8 (java.lang.Integer/parseInt minor)) + ["-Djava.security.properties==dev-resources/jdk8-fips-security"] + (throw unsupported-ex)) + 11 ["-Djava.security.properties==dev-resources/jdk11-fips-security"] + 17 ["-Djava.security.properties==dev-resources/jdk17-fips-security"] + (throw unsupported-ex)))} + :fips [:defaults :fips-deps] :sources-jar {:java-source-paths ^:replace [] :jar-exclusions ^:replace [] :source-paths ^:replace ["src/clj" "src/java"]}}