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..6bd04d0 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,25 @@ (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" "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"] + "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"] :c "1,2" :d "123"} + (:body response))))))) \ No newline at end of file