-
Notifications
You must be signed in to change notification settings - Fork 519
/
codec.clj
113 lines (100 loc) · 3.62 KB
/
codec.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
(ns ring.util.codec
"Encoding and decoding utilities."
(: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))
(defn- double-escape [^String x]
(.replace (.replace x "\\" "\\\\") "$" "\\$"))
(defn percent-encode
"Percent-encode every character in the given string using either the specified
encoding, or UTF-8 by default."
[unencoded & [encoding]]
(->> (.getBytes unencoded (or encoding "UTF-8"))
(map (partial format "%%%02X"))
(str/join)))
(defn- parse-bytes [encoded-bytes]
(->> (re-seq #"%.." encoded-bytes)
(map #(subs % 1))
(map #(.byteValue (Integer/parseInt % 16)))
(byte-array)))
(defn percent-decode
"Decode every percent-encoded character in the given string using the
specified encoding, or UTF-8 by default."
[encoded & [encoding]]
(str/replace encoded
#"(?:%..)+"
(fn [chars]
(-> (parse-bytes chars)
(String. (or encoding "UTF-8"))
(double-escape)))))
(defn url-encode
"Returns the url-encoded version of the given string, using either a specified
encoding or UTF-8 by default."
[unencoded & [encoding]]
(str/replace
unencoded
#"[^A-Za-z0-9_~.+-]+"
#(double-escape (percent-encode % encoding))))
(defn url-decode
"Returns the url-decoded version of the given string, using either a specified
encoding or UTF-8 by default. If the encoding is invalid, nil is returned."
[encoded & [encoding]]
(percent-decode encoded encoding))
(defn base64-encode
"Encode an array of bytes into a base64 encoded string."
[unencoded]
(String. (Base64/encodeBase64 unencoded)))
(defn base64-decode
"Decode a base64 encoded string into an array of bytes."
[^String encoded]
(Base64/decodeBase64 (.getBytes encoded)))
(defprotocol FormEncodeable
(form-encode* [x encoding]))
(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-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."
[encoded & [encoding]]
(if-not (.contains encoded "=")
(form-decode-str encoded encoding)
(reduce
(fn [m param]
(if-let [[k v] (str/split param #"=" 2)]
(assoc-conj m (form-decode-str k encoding) (form-decode-str v encoding))
m))
{}
(str/split encoded #"&"))))