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
|
||||
;;
|
||||
|
||||
#?(: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]
|
||||
(some-> s
|
||||
#?(:clj (URLEncoder/encode "UTF-8")
|
||||
:cljs (js/encodeURIComponent))
|
||||
#?(:clj (.replace "+" "%20"))))
|
||||
(if s
|
||||
#?(:clj (str/replace s #"[^A-Za-z0-9\!'\(\)\*_~.-]+" percent-encode)
|
||||
:cljs (js/encodeURIComponent s))))
|
||||
|
||||
(defn url-decode [s]
|
||||
(some-> s #?(:clj (URLDecoder/decode "UTF-8")
|
||||
:cljs (js/decodeURIComponent))))
|
||||
(if s
|
||||
#?(: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
|
||||
(into-string [_]))
|
||||
|
|
@ -203,7 +228,7 @@
|
|||
(into-string [this] (str this))
|
||||
|
||||
nil
|
||||
(into-string [this]))
|
||||
(into-string [_]))
|
||||
|
||||
(defn path-params
|
||||
"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 (seq [1 2])} "a=1&a=2"
|
||||
;{: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