Skip to content

Commit

Permalink
Protocol for form-encode to support strings and maps
Browse files Browse the repository at this point in the history
  • Loading branch information
weavejester committed Mar 24, 2012
1 parent 98bb0b9 commit 053832d
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 20 deletions.
50 changes: 30 additions & 20 deletions ring-core/src/ring/util/codec.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
(:use ring.util.data)
(:require [clojure.string :as str])
(:import java.io.File
java.util.Map
(java.net URLEncoder URLDecoder)
org.apache.commons.codec.binary.Base64))

Expand Down Expand Up @@ -59,6 +60,35 @@
[^String encoded]
(Base64/decodeBase64 (.getBytes encoded)))

(defprotocol FormEncodeable
(form-encode* [x encoding]))

(defn form-encode
"Encode the supplied value into www-form-urlencoded format, often used in
URL query strings and POST request bodies, using the specified encoding.
If the encoding is not specified, it defaults to UTF-8"
[x & [encoding]]
(form-encode* x (or encoding "UTF-8")))

(extend-protocol FormEncodeable
String
(form-encode* [unencoded encoding]
(URLEncoder/encode unencoded encoding))
Map
(form-encode* [params encoding]
(letfn [(encode [x] (form-encode x encoding))
(encode-param [[k v]] (str (encode (name k)) "=" (encode v)))]
(->> params
(mapcat
(fn [[k v]]
(if (or (seq? v) (sequential? v) )
(map #(encode-param [k %]) v)
[(encode-param [k v])])))
(str/join "&"))))
Object
(form-encode* [x encoding]
(form-encode* (str x) encoding)))

(defn form-decode
"Parse parameters from a string into a map."
([^String param-string]
Expand All @@ -73,23 +103,3 @@
param-map))
{}
(str/split param-string #"&"))))

(defn form-encode
"Encode parameters from a map into a string."
([param-map]
(form-encode param-map "UTF-8"))
([param-map encoding]
(form-encode (keys param-map)
(vals param-map)
encoding))
([params values encoding]
(str/join #"&"
(map (fn [param value]
(if (vector? value)
(form-encode (repeat (count value) param)
value
encoding)
(str (url-encode param)
"="
(url-encode value))))
params values))))
16 changes: 16 additions & 0 deletions ring-core/test/ring/util/test/codec.clj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@
(let [str-bytes (.getBytes "foo?/+" "UTF-8")]
(is (Arrays/equals str-bytes (base64-decode (base64-encode str-bytes))))))

(deftest test-form-encode
(testing "strings"
(are [x y] (= (form-encode x) y)
"foo bar" "foo+bar"
"foo+bar" "foo%2Bbar"
"foo/bar" "foo%2Fbar")
(is (= (form-encode "foo/bar" "UTF-16") "foo%FE%FF%00%2Fbar")))
(testing "maps"
(are [x y] (= (form-encode x) y)
{"a" "b"} "a=b"
{:a "b"} "a=b"
{"a" 1} "a=1"
{"a" "b" "c" "d"} "a=b&c=d"
{"a" "b c"} "a=b+c")
(is (= (form-encode {"a" "foo/bar"} "UTF-16") "a=foo%FE%FF%00%2Fbar"))))

(deftest form-encoding
(let [encoded-params "p%2F1=v%2F1&p%2F2=v%2F21&p%2F2=v%2F22"]
(is (= (form-decode encoded-params)
Expand Down

0 comments on commit 053832d

Please sign in to comment.