             (assoc m (if keywordize-headers? (keyword (str/lower-case k))
                          (str/lower-case k)) v))
           {} headers))
+
+(defn- url-encode [unencoded] (URLEncoder/encode unencoded "UTF-8"))
+(defn- utf8-bytes [#^String s] (.getBytes s "UTF-8"))
+(defn- base64-encode [bytes]
+  (DatatypeConverter/printBase64Binary bytes))
+(defn- basic-auth-value [basic-auth]
+  (let [basic-auth (if (string? basic-auth)
+                     basic-auth
+                     (str (first basic-auth) ":" (second basic-auth)))]
+    (str "Basic " (base64-encode (utf8-bytes basic-auth)))))
+
+(defn- form-body [params]
+  (.getBytes (str/join "&"
+                       (mapcat (fn [[k v]]
+                                 (if (sequential? v)
+                                   (map #(str (url-encode (name %1))
+                                              "="
+                                              (url-encode (str %2)))
+                                        (repeat k) v)
+                                   [(str (url-encode (name k))
+                                         "="
+                                         (url-encode (str v)))]))
+                               params))
+             "UTF-8"))
 
 (defonce default-client (atom nil))
 

(ns me.shenfeng.http.client
  (:require [clojure.string :as str])
  (:import [me.shenfeng.http.client HttpClientConfig HttpClient
            IResponseHandler RespListener RespListener$IFilter]
           (java.net URI URLEncoder)
           me.shenfeng.http.HttpMethod))


  [options resp & handler]
  `(request* ~options (fn [~resp] ~@handler)))

(defmacro get
  ([url]
     `(request {:method :get :url ~url} resp# nil))
  ([url req]
     `(get ~url ~req resp# nil))
  ([url req resp & forms]
     `(let [req# (assoc ~req :method :get :url ~url)]
        (request req#  ~resp ~@forms))))

(defmacro post
  ([url]
     `(request {:method :post :url ~url} resp# nil))
  ([url req]
     `(post ~url ~req resp# nil))
  ([url req resp & forms]
     `(let [req# (merge {:method :post :url ~url} ~req)]
        (request req# ~resp ~@forms))))

(comment
  (let [a (post "http://127.0.0.1:9091" {:timeout 900
                                         :form-params {:param1 "abc" :param2 ["a" "b"]}
                                         :basic-auth ["user" "password"]}
                {:keys [status headers body] :as resp}
                (if status
                  (println status)
                  (do (.printStackTrace resp))))]
    (println @a)))
