mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 00:11:11 +00:00
url-encode & url-decode
This commit is contained in:
parent
bb4f861f00
commit
0b4d1d2ee1
3 changed files with 241 additions and 7 deletions
|
|
@ -166,15 +166,40 @@
|
||||||
;; Path-parameters, see https://github.com/metosin/reitit/issues/75
|
;; Path-parameters, see https://github.com/metosin/reitit/issues/75
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(def hex-digit
|
||||||
|
{0 "0" 1 "1" 2 "2" 3 "3"
|
||||||
|
4 "4" 5 "5" 6 "6" 7 "7"
|
||||||
|
8 "8" 9 "9" 10 "A" 11 "B"
|
||||||
|
12 "C" 13 "D" 14 "E" 15 "F"}))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn byte->percent [byte]
|
||||||
|
(let [byte (bit-and 0xFF byte)
|
||||||
|
low-nibble (bit-and 0xF byte)
|
||||||
|
high-nibble (bit-shift-right byte 4)]
|
||||||
|
(str "%" (hex-digit high-nibble) (hex-digit low-nibble)))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn percent-encode [^String unencoded]
|
||||||
|
(->> (.getBytes unencoded "UTF-8") (map byte->percent) (str/join))))
|
||||||
|
|
||||||
|
;; + is safe, but removed so it would work the same as with js
|
||||||
(defn url-encode [s]
|
(defn url-encode [s]
|
||||||
(some-> s
|
(if s
|
||||||
#?(:clj (URLEncoder/encode "UTF-8")
|
#?(:clj (str/replace s #"[^A-Za-z0-9\!'\(\)\*_~.-]+" percent-encode)
|
||||||
:cljs (js/encodeURIComponent))
|
:cljs (js/encodeURIComponent s))))
|
||||||
#?(:clj (.replace "+" "%20"))))
|
|
||||||
|
|
||||||
(defn url-decode [s]
|
(defn url-decode [s]
|
||||||
(some-> s #?(:clj (URLDecoder/decode "UTF-8")
|
(if s
|
||||||
:cljs (js/decodeURIComponent))))
|
#?(:clj (if (.contains ^String s "%")
|
||||||
|
(URLDecoder/decode
|
||||||
|
(if (.contains ^String s "+")
|
||||||
|
(.replace ^String s "+" "%2B")
|
||||||
|
s)
|
||||||
|
"UTF-8")
|
||||||
|
s)
|
||||||
|
:cljs (js/decodeURIComponent s))))
|
||||||
|
|
||||||
(defprotocol IntoString
|
(defprotocol IntoString
|
||||||
(into-string [_]))
|
(into-string [_]))
|
||||||
|
|
@ -203,7 +228,7 @@
|
||||||
(into-string [this] (str this))
|
(into-string [this] (str this))
|
||||||
|
|
||||||
nil
|
nil
|
||||||
(into-string [this]))
|
(into-string [_]))
|
||||||
|
|
||||||
(defn path-params
|
(defn path-params
|
||||||
"shallow transform of the path parameters values into strings"
|
"shallow transform of the path parameters values into strings"
|
||||||
|
|
|
||||||
116
perf-test/clj/reitit/impl_perf_test.clj
Normal file
116
perf-test/clj/reitit/impl_perf_test.clj
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
(ns reitit.impl-perf-test
|
||||||
|
(:require [criterium.core :as cc]
|
||||||
|
[reitit.perf-utils :refer :all]
|
||||||
|
[ring.util.codec]
|
||||||
|
[reitit.impl])
|
||||||
|
(:import (java.net URLDecoder URLEncoder)))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; start repl with `lein perf repl`
|
||||||
|
;; perf measured with the following setup:
|
||||||
|
;;
|
||||||
|
;; Model Name: MacBook Pro
|
||||||
|
;; Model Identifier: MacBookPro11,3
|
||||||
|
;; Processor Name: Intel Core i7
|
||||||
|
;; Processor Speed: 2,5 GHz
|
||||||
|
;; Number of Processors: 1
|
||||||
|
;; Total Number of Cores: 4
|
||||||
|
;; L2 Cache (per Core): 256 KB
|
||||||
|
;; L3 Cache: 6 MB
|
||||||
|
;; Memory: 16 GB
|
||||||
|
;;
|
||||||
|
|
||||||
|
|
||||||
|
(defn test! [f input]
|
||||||
|
(do
|
||||||
|
(println "\u001B[33m")
|
||||||
|
(println (pr-str input) "=>" (pr-str (f input)))
|
||||||
|
(println "\u001B[0m")
|
||||||
|
(cc/quick-bench (f input))))
|
||||||
|
|
||||||
|
(defn url-decode-naive [s]
|
||||||
|
(URLDecoder/decode
|
||||||
|
(.replace ^String s "+" "%2B")
|
||||||
|
"UTF-8"))
|
||||||
|
|
||||||
|
(defn decode! []
|
||||||
|
|
||||||
|
;; ring
|
||||||
|
|
||||||
|
;; 890ns
|
||||||
|
;; 190ns
|
||||||
|
;; 90ns
|
||||||
|
;; 80ns
|
||||||
|
|
||||||
|
;; naive
|
||||||
|
|
||||||
|
;; 750ns
|
||||||
|
;; 340ns
|
||||||
|
;; 420ns
|
||||||
|
;; 200ns
|
||||||
|
|
||||||
|
;; reitit
|
||||||
|
|
||||||
|
;; 630ns (-29%)
|
||||||
|
;; 12ns (-94%)
|
||||||
|
;; 8ns (-91%)
|
||||||
|
;; 8ns (-90%)
|
||||||
|
|
||||||
|
(doseq [fs ['ring.util.codec/url-decode
|
||||||
|
'url-decode-naive
|
||||||
|
'reitit.impl/url-decode]
|
||||||
|
:let [f (deref (resolve fs))]]
|
||||||
|
(suite (str fs))
|
||||||
|
(doseq [s ["aja%20hiljaa+sillalla"
|
||||||
|
"aja_hiljaa_sillalla"
|
||||||
|
"1+1"
|
||||||
|
"1"]]
|
||||||
|
(test! f s))))
|
||||||
|
|
||||||
|
(defn url-encode-naive [^String s]
|
||||||
|
(cond-> (.replace (URLEncoder/encode s "UTF-8") "+" "%20")
|
||||||
|
(.contains s "+") (.replace "%2B" "+")
|
||||||
|
(.contains s "~") (.replace "%7E" "~")
|
||||||
|
(.contains s "=") (.replace "%3D" "=")
|
||||||
|
(.contains s "!") (.replace "%21" "!")
|
||||||
|
(.contains s "'") (.replace "%27" "'")
|
||||||
|
(.contains s "(") (.replace "%28" "(")
|
||||||
|
(.contains s ")") (.replace "%29" ")")))
|
||||||
|
|
||||||
|
(defn encode! []
|
||||||
|
|
||||||
|
;; ring
|
||||||
|
|
||||||
|
;; 2500ns
|
||||||
|
;; 610ns
|
||||||
|
;; 160ns
|
||||||
|
;; 120ns
|
||||||
|
|
||||||
|
;; naive
|
||||||
|
|
||||||
|
;; 1000ns
|
||||||
|
;; 440ns
|
||||||
|
;; 570ns
|
||||||
|
;; 200ns
|
||||||
|
|
||||||
|
;; reitit
|
||||||
|
|
||||||
|
;; 1400ns
|
||||||
|
;; 740ns
|
||||||
|
;; 180ns
|
||||||
|
;; 130ns
|
||||||
|
|
||||||
|
(doseq [fs ['ring.util.codec/url-encode
|
||||||
|
'url-encode-naive
|
||||||
|
'reitit.impl/url-encode]
|
||||||
|
:let [f (deref (resolve fs))]]
|
||||||
|
(suite (str fs))
|
||||||
|
(doseq [s ["aja hiljaa+sillalla"
|
||||||
|
"aja_hiljaa_sillalla"
|
||||||
|
"1+1"
|
||||||
|
"1"]]
|
||||||
|
(test! f s))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(decode!)
|
||||||
|
(encode!))
|
||||||
|
|
@ -64,3 +64,96 @@
|
||||||
;{:a ["c" "b"]} "a=c&a=b"
|
;{:a ["c" "b"]} "a=c&a=b"
|
||||||
;{:a (seq [1 2])} "a=1&a=2"
|
;{:a (seq [1 2])} "a=1&a=2"
|
||||||
;{:a #{"c" "b"}} "a=b&a=c"
|
;{:a #{"c" "b"}} "a=b&a=c"
|
||||||
|
|
||||||
|
(deftest url-encode-test
|
||||||
|
(are [in out]
|
||||||
|
(= out (impl/url-encode in))
|
||||||
|
|
||||||
|
"/" "%2F"
|
||||||
|
"?" "%3F"
|
||||||
|
"#" "%23"
|
||||||
|
"[" "%5B"
|
||||||
|
"]" "%5D"
|
||||||
|
"!" "!"
|
||||||
|
#_#_"$" "$"
|
||||||
|
#_#_"&" "&"
|
||||||
|
"'" "'"
|
||||||
|
"(" "("
|
||||||
|
")" ")"
|
||||||
|
"*" "*"
|
||||||
|
#_#_"+" "+"
|
||||||
|
#_#_"," ","
|
||||||
|
#_#_";" ";"
|
||||||
|
#_#_"=" "="
|
||||||
|
#_#_":" ":"
|
||||||
|
#_#_"@" "@"
|
||||||
|
"a" "a"
|
||||||
|
"z" "z"
|
||||||
|
"A" "A"
|
||||||
|
"Z" "Z"
|
||||||
|
"0" "0"
|
||||||
|
"9" "9"
|
||||||
|
"-" "-"
|
||||||
|
"." "."
|
||||||
|
"_" "_"
|
||||||
|
"~" "~"
|
||||||
|
"\000" "%00"
|
||||||
|
"\037" "%1F"
|
||||||
|
" " "%20"
|
||||||
|
"\"" "%22"
|
||||||
|
"%" "%25"
|
||||||
|
"<" "%3C"
|
||||||
|
">" "%3E"
|
||||||
|
"\\" "%5C"
|
||||||
|
"^" "%5E"
|
||||||
|
"`" "%60"
|
||||||
|
"{" "%7B"
|
||||||
|
"|" "%7C"
|
||||||
|
"}" "%7D"
|
||||||
|
"\177" "%7F"
|
||||||
|
#_#_"\377" "%FF"
|
||||||
|
|
||||||
|
"£0.25" "%C2%A30.25"
|
||||||
|
"€100" "%E2%82%AC100"
|
||||||
|
"«küßî»" "%C2%ABk%C3%BC%C3%9F%C3%AE%C2%BB"
|
||||||
|
"“ЌύБЇ”" "%E2%80%9C%D0%8C%CF%8D%D0%91%D0%87%E2%80%9D"
|
||||||
|
|
||||||
|
"\000" "%00"
|
||||||
|
#_#_"\231" "%99"
|
||||||
|
#_#_"\252" "%AA"
|
||||||
|
#_#_"\377" "%FF"
|
||||||
|
|
||||||
|
"" ""
|
||||||
|
"1" "1"
|
||||||
|
"12" "12"
|
||||||
|
"123" "123"
|
||||||
|
"1234567890" "1234567890"
|
||||||
|
|
||||||
|
"Hello world" "Hello%20world"
|
||||||
|
"/home/foo" "%2Fhome%2Ffoo"
|
||||||
|
|
||||||
|
" " "%20"
|
||||||
|
"+" "%2B" #_"+"
|
||||||
|
" +" "%20%2B" #_"%20+"
|
||||||
|
#_#_"1+2=3" "1+2=3"
|
||||||
|
#_#_"1 + 2 = 3" "1%20+%202%20=%203"))
|
||||||
|
|
||||||
|
(deftest url-decode-test
|
||||||
|
(are [in out]
|
||||||
|
(= out (impl/url-decode in))
|
||||||
|
|
||||||
|
"1+1" "1+1"
|
||||||
|
"%21" "!"
|
||||||
|
"%61" "a"
|
||||||
|
"%31%32%33" "123"
|
||||||
|
"%2b" "+"
|
||||||
|
"%7e" "~"
|
||||||
|
"hello%20world" "hello world"
|
||||||
|
"a%2fb" "a/b"
|
||||||
|
"a/.." "a/.."
|
||||||
|
"a/." "a/."
|
||||||
|
"//a" "//a"
|
||||||
|
"a//b" "a//b"
|
||||||
|
"a//" "a//"
|
||||||
|
"/path/%C2%ABk%C3%BC%C3%9F%C3%AE%C2%BB" "/path/«küßî»"
|
||||||
|
"/path/%E2%80%9C%D0%8C%CF%8D%D0%91%D0%87%E2%80%9D" "/path/“ЌύБЇ”"))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue