From cd406d706109e781c368c3d98815702c81e59d94 Mon Sep 17 00:00:00 2001 From: Vincent Pizzo Date: Fri, 2 Jun 2023 11:32:20 -0700 Subject: [PATCH 1/2] Allow a header's value to be a seq of src to match clj-http and multi-valued header responses --- README.md | 4 ++-- src/hato/client.clj | 10 ++++++++-- test/hato/client_test.clj | 23 ++++++++++++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 63c1e54..39f9da7 100644 --- a/README.md +++ b/README.md @@ -185,8 +185,8 @@ request and returns a response. Convenience wrappers are provided for the http v will depend on `:content`. When `:content` is a `String`, it will be `text/plain; charset=UTF-8` and when `:content` is a `File`, it will attempt to guess the best content type or fallback to `application/octet-stream`. -`headers` Map of lower case strings to header values, concatenated with ',' when multiple values for a key. - This is presently a slight incompatibility with clj-http, which accepts keyword keys and list values. +`headers` Map of lower case strings to a header value. A header's value may be a string or a sequence of strings when + there are multiple values for a given header. `basic-auth` Performs basic authentication (sending `Basic` authorization header). Accepts `{:user "user" :pass "pass"}` Note that basic auth can also be passed via the `url` (e.g. `http://user:pass@moo.com`) diff --git a/src/hato/client.clj b/src/hato/client.clj index f28150c..a38f476 100644 --- a/src/hato/client.clj +++ b/src/hato/client.clj @@ -187,8 +187,14 @@ (defn- with-headers ^HttpRequest$Builder [builder headers] (reduce-kv - (fn [^HttpRequest$Builder b ^String hk ^String hv] - (.header b hk hv)) + (fn [^HttpRequest$Builder b ^String hk hv] + (if (sequential? hv) + (reduce + (fn [^HttpRequest$Builder acc-b shv] + (.header acc-b hk (str shv))) + b + hv) + (.header b hk (str hv)))) builder headers)) diff --git a/test/hato/client_test.clj b/test/hato/client_test.clj index e8463bb..60ab0a7 100644 --- a/test/hato/client_test.clj +++ b/test/hato/client_test.clj @@ -1,6 +1,7 @@ (ns hato.client-test (:refer-clojure :exclude [get]) - (:require [clojure.test :refer :all] + (:require [clojure.string :as str] + [clojure.test :refer :all] [hato.client :refer :all] [clojure.java.io :as io] [org.httpkit.server :as http-kit] @@ -339,3 +340,23 @@ (fn [req] ::response))]})] (is (= ::response r)))) + +(deftest multi-value-headers + (testing "We can send and receive multi-value headers" + (with-server (fn app [req] + {:status 200 + :headers {"foo" ["bar" "baz"] + "content-type" "application/json"} + :body (json/generate-string + (-> (:headers req) + (select-keys ["a" "b"]) + ;; ring spec will take multi value headers as a comma separated string. + (update "b" #(str/split % #","))))}) + (let [response (get "http://localhost:1234" {:headers {"a" "single" + "b" ["1" "2"]} + :as :json})] + (is (= {"content-type" "application/json" + "foo" ["bar" "baz"]} + (select-keys (:headers response) ["foo" "content-type"]))) + (is (= {:a "single" :b ["1" "2"]} + (:body response))))))) \ No newline at end of file From 278abe9fcb1b01804863d627266b7fe925ce980a Mon Sep 17 00:00:00 2001 From: Vincent Pizzo Date: Fri, 2 Jun 2023 11:38:25 -0700 Subject: [PATCH 2/2] Add test for comma separated header and numeric value as well --- test/hato/client_test.clj | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/hato/client_test.clj b/test/hato/client_test.clj index 60ab0a7..6bd04d0 100644 --- a/test/hato/client_test.clj +++ b/test/hato/client_test.clj @@ -349,14 +349,16 @@ "content-type" "application/json"} :body (json/generate-string (-> (:headers req) - (select-keys ["a" "b"]) + (select-keys ["a" "b" "c" "d"]) ;; ring spec will take multi value headers as a comma separated string. (update "b" #(str/split % #","))))}) (let [response (get "http://localhost:1234" {:headers {"a" "single" - "b" ["1" "2"]} + "b" ["1" "2"] + "c" "1,2" + "d" 123} :as :json})] (is (= {"content-type" "application/json" "foo" ["bar" "baz"]} (select-keys (:headers response) ["foo" "content-type"]))) - (is (= {:a "single" :b ["1" "2"]} + (is (= {:a "single" :b ["1" "2"] :c "1,2" :d "123"} (:body response))))))) \ No newline at end of file