|
2 | 2 | "Functions for encoding and decoding data." |
3 | 3 | (:require [clojure.string :as str]) |
4 | 4 | (:import java.util.Map |
| 5 | + clojure.lang.MapEntry |
5 | 6 | [java.net URLEncoder URLDecoder] |
6 | | - [java.util Base64])) |
| 7 | + [java.util Base64 StringTokenizer])) |
7 | 8 |
|
8 | 9 | (defn assoc-conj |
9 | 10 | "Associate a key with a value in a map. If the key already exists in the map, |
|
129 | 130 | (URLDecoder/decode encoded encoding) |
130 | 131 | (catch Exception _ nil)))) |
131 | 132 |
|
| 133 | +(defn- tokenized [s delim] |
| 134 | + (reify clojure.lang.IReduceInit |
| 135 | + (reduce [_ f init] |
| 136 | + (let [tokenizer (StringTokenizer. s delim)] |
| 137 | + (loop [result init] |
| 138 | + (if (.hasMoreTokens tokenizer) |
| 139 | + (recur (f result (.nextToken tokenizer))) |
| 140 | + result)))))) |
| 141 | + |
| 142 | +(defn- split-key-value-pair [^String s] |
| 143 | + (let [i (.indexOf s #=(int \=))] |
| 144 | + (cond |
| 145 | + (pos? i) (MapEntry. (.substring s 0 i) (.substring s (inc i))) |
| 146 | + (zero? i) (MapEntry. "" (.substring s (inc i))) |
| 147 | + :else (MapEntry. s "")))) |
| 148 | + |
132 | 149 | (defn form-decode |
133 | 150 | "Decode the supplied www-form-urlencoded string using the specified encoding, |
134 | 151 | or UTF-8 by default. If the encoded value is a string, a string is returned. |
|
140 | 157 | (form-decode-str encoded encoding) |
141 | 158 | (reduce |
142 | 159 | (fn [m param] |
143 | | - (let [[k v] (str/split param #"=" 2) |
144 | | - k (form-decode-str k encoding) |
145 | | - v (form-decode-str (or v "") encoding)] |
| 160 | + (let [kv (split-key-value-pair param) |
| 161 | + k (form-decode-str (key kv) encoding) |
| 162 | + v (form-decode-str (val kv) encoding)] |
146 | 163 | (if (and k v) |
147 | 164 | (assoc-conj m k v) |
148 | 165 | m))) |
149 | 166 | {} |
150 | | - (str/split encoded #"&"))))) |
| 167 | + (tokenized encoded "&"))))) |
0 commit comments