1 ! Copyright (C) 2008, 2010 Slava Pestov.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: arrays ascii assocs byte-arrays combinators
4 combinators.short-circuit io.encodings io.encodings.string
5 io.encodings.utf8 kernel linked-assocs make math math.parser
6 namespaces present sequences sequences.private splitting strings ;
9 : url-quotable? ( ch -- ? )
17 ! see https://tools.ietf.org/html/rfc3986#section-2.2
18 : gen-delim? ( ch -- ? )
19 ":/?#[]@" member? ; foldable
21 : sub-delim? ( ch -- ? )
22 "!$&'()*+,;=" member? ; foldable
24 : reserved? ( ch -- ? )
25 [ gen-delim? ] [ sub-delim? ] bi or ; foldable
27 ! see https://tools.ietf.org/html/rfc3986#section-2.3
28 : unreserved? ( ch -- ? )
39 CHAR: % , >hex >upper 2 CHAR: 0 pad-head % ;
42 1string utf8 encode [ hex% ] each ;
44 : (url-encode) ( str quot: ( ch -- ? ) -- encoded )
47 '[ dup @ [ , ] [ hex% ] if ] each
50 '[ dup @ [ , ] [ hex-utf8% ] if ] each
56 : url-encode ( obj -- encoded )
57 [ url-quotable? ] (url-encode) ;
59 : url-encode-full ( obj -- encoded )
60 [ unreserved? ] (url-encode) ;
65 building get utf8 encode-char ;
67 : url-decode-hex ( index str -- )
71 [ 1 + dup 2 + ] dip <slice> hex> [ , ] when*
74 : url-decode-iter ( index str -- )
78 2dup nth-unsafe dup CHAR: % = [
79 drop 2dup url-decode-hex [ 3 + ] dip
83 ] if ; inline recursive
87 : url-decode ( str -- decoded )
88 [ 0 swap url-decode-iter ] "" make utf8 decode ;
92 : add-query-param ( value key assoc -- )
95 { [ dup string? ] [ swap 2array ] }
96 { [ dup array? ] [ swap suffix ] }
97 { [ dup not ] [ drop ] }
103 : query-decode ( str -- decoded )
104 "+" split "%20" join url-decode ;
106 : query>assoc ( query -- assoc )
108 "&" split <linked-hash> [
110 [ "=" split1 [ dup [ query-decode ] when ] bi@ swap ] dip
116 : assoc>query ( assoc -- str )
119 [ url-encode-full ] dip [
120 dup array? [ 1array ] unless
121 [ url-encode-full "=" glue , ] with each
124 ] { } make "&" join ;
126 : escape-uri-component-char? ( ch -- ? )
131 [ "-_.!~*'()" member? ]
134 : encode-uri-component ( str -- str' )
136 [ dup escape-uri-component-char? [ hex-utf8% ] [ , ] if ] each
139 : escape-uri-char? ( ch -- ? )
144 [ ";,/?:@&=+$-_.!~*'()#" member? ]
147 : encode-uri ( str -- str' )
149 [ dup escape-uri-char? [ hex-utf8% ] [ , ] if ] each
154 : decode-uri-hex ( index str quot: ( ch -- ? ) -- )
159 [ 1 + dup 2 + ] dip <slice>
160 dup hex> dup @ [ nip , ] [ CHAR: % , drop % ] if
164 : decode-uri-iter ( index str quot: ( ch -- ? ) -- )
169 2dup nth-unsafe dup CHAR: % = [
170 drop 2dup _ decode-uri-hex [ 3 + ] dip
173 ] if _ decode-uri-iter
175 ] call ; inline recursive
179 : decode-uri-component ( str -- decoded )
180 [ 0 swap [ escape-uri-component-char? ] decode-uri-iter ] "" make utf8 decode ;
182 : decode-uri ( str -- decoded )
183 [ 0 swap [ escape-uri-char? ] decode-uri-iter ] "" make utf8 decode ;