diff --git a/ring-core/src/ring/middleware/cookies.clj b/ring-core/src/ring/middleware/cookies.clj index 5c995a7..d1a5ec2 100644 --- a/ring-core/src/ring/middleware/cookies.clj +++ b/ring-core/src/ring/middleware/cookies.clj @@ -50,7 +50,7 @@ [cookies] (remove nil? (for [[name value] cookies] - (if-let [value (codec/url-decode value)] + (if-let [value (codec/form-decode-str value)] (if (.startsWith ^String value "\"") [name (read-string value)] [name value]))))) @@ -88,7 +88,7 @@ (defn- write-value "Write the main cookie value." [key value] - (str (name key) "=" (codec/url-encode value))) + (codec/form-encode {key value})) (defn- valid-attr? "Is the attribute valid?" diff --git a/ring-core/src/ring/middleware/params.clj b/ring-core/src/ring/middleware/params.clj index 60b79f7..171180d 100644 --- a/ring-core/src/ring/middleware/params.clj +++ b/ring-core/src/ring/middleware/params.clj @@ -2,12 +2,16 @@ "Parse form and query params." (:require [ring.util.codec :as codec])) +(defn- parse-params [params encoding] + (let [params (codec/form-decode params encoding)] + (if (map? params) params {}))) + (defn- assoc-query-params "Parse and assoc parameters from the query string with the request." [request encoding] (merge-with merge request (if-let [query-string (:query-string request)] - (let [params (codec/form-decode query-string encoding)] + (let [params (parse-params query-string encoding)] {:query-params params, :params params}) {:query-params {}, :params {}}))) @@ -22,7 +26,7 @@ [request encoding] (merge-with merge request (if-let [body (and (urlencoded-form? request) (:body request))] - (let [params (codec/form-decode (slurp body :encoding encoding) encoding)] + (let [params (parse-params (slurp body :encoding encoding) encoding)] {:form-params params, :params params}) {:form-params {}, :params {}}))) diff --git a/ring-core/src/ring/util/codec.clj b/ring-core/src/ring/util/codec.clj index cb65281..8565492 100644 --- a/ring-core/src/ring/util/codec.clj +++ b/ring-core/src/ring/util/codec.clj @@ -63,20 +63,13 @@ (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)) + (letfn [(encode [x] (form-encode* x encoding)) (encode-param [[k v]] (str (encode (name k)) "=" (encode v)))] (->> params (mapcat @@ -89,18 +82,32 @@ (form-encode* [x encoding] (form-encode* (str 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"))) + +(defn form-decode-str + "Decode the supplied www-form-urlencoded string using the specified encoding, + or UTF-8 by default." + [^String encoded & [encoding]] + (try + (URLDecoder/decode encoded (or encoding "UTF-8")) + (catch Exception _ nil))) + (defn form-decode "Decode the supplied www-form-urlencoded string using the specified encoding, or UTF-8 by default. If the encoded value is a string, a string is returned. If the encoded value is a map of parameters, a map is returned." - [^String encoded & [encoding]] - (letfn [(decode [s] (URLDecoder/decode s (or encoding "UTF-8")))] - (if-not (.contains encoded "=") - (decode encoded) - (reduce - (fn [m param] - (if-let [[k v] (str/split param #"=" 2)] - (assoc+ m (decode k) (decode v)) - m)) - {} - (str/split encoded #"&"))))) + [encoded & [encoding]] + (if-not (.contains encoded "=") + (form-decode-str encoded encoding) + (reduce + (fn [m param] + (if-let [[k v] (str/split param #"=" 2)] + (assoc+ m (form-decode-str k encoding) (form-decode-str v encoding)) + m)) + {} + (str/split encoded #"&")))) diff --git a/ring-core/test/ring/util/test/codec.clj b/ring-core/test/ring/util/test/codec.clj index 7fd0c40..b431d2d 100644 --- a/ring-core/test/ring/util/test/codec.clj +++ b/ring-core/test/ring/util/test/codec.clj @@ -44,6 +44,10 @@ {"a" "b c"} "a=b+c") (is (= (form-encode {"a" "foo/bar"} "UTF-16") "a=foo%FE%FF%00%2Fbar")))) +(deftest test-form-decode-str + (is (= (form-decode-str "foo=bar+baz") "foo=bar baz")) + (is (nil? (form-decode-str "%D")))) + (deftest test-form-decode (are [x y] (= (form-decode x) y) "foo" "foo"