Merges #7700 manually and adds decodePlus option to decodeUrl too.
This commit is contained in:
parent
5564289b57
commit
9099ec5d0b
1 changed files with 33 additions and 15 deletions
|
|
@ -47,25 +47,36 @@ proc add*(url: var Url, a: Url) {.deprecated.} =
|
||||||
url = url / a
|
url = url / a
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc encodeUrl*(s: string): string =
|
proc encodeUrl*(s: string, usePlus=true): string =
|
||||||
## Encodes a value to be HTTP safe: This means that characters in the set
|
## Encodes a URL according to RFC3986.
|
||||||
## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result,
|
##
|
||||||
## a space is converted to ``'+'`` and every other character is encoded as
|
## This means that characters in the set
|
||||||
## ``'%xx'`` where ``xx`` denotes its hexadecimal value.
|
## ``{'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~'}`` are
|
||||||
|
## carried over to the result.
|
||||||
|
## All other characters are encoded as ``''%xx'`` where ``xx``
|
||||||
|
## denotes its hexadecimal value.
|
||||||
|
##
|
||||||
|
## As a special rule, when the value of ``usePlus`` is true,
|
||||||
|
## spaces are encoded as ``'+'`` instead of ``'%20'``.
|
||||||
result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars
|
result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars
|
||||||
for i in 0..s.len-1:
|
let fromSpace = if usePlus: "+" else: "%20"
|
||||||
case s[i]
|
for c in s:
|
||||||
of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
|
case c
|
||||||
of ' ': add(result, '+')
|
of 'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~': add(result, c)
|
||||||
|
of ' ': add(result, fromSpace)
|
||||||
else:
|
else:
|
||||||
add(result, '%')
|
add(result, '%')
|
||||||
add(result, toHex(ord(s[i]), 2))
|
add(result, toHex(ord(c), 2))
|
||||||
|
|
||||||
proc decodeUrl*(s: string): string =
|
proc decodeUrl*(s: string, decodePlus=true): string =
|
||||||
## Decodes a value from its HTTP representation: This means that a ``'+'``
|
## Decodes a URL according to RFC3986.
|
||||||
## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
|
##
|
||||||
## value) is converted to the character with ordinal number ``xx``, and
|
## This means that any ``'%xx'`` (where ``xx`` denotes a hexadecimal
|
||||||
|
## value) are converted to the character with ordinal number ``xx``,
|
||||||
## and every other character is carried over.
|
## and every other character is carried over.
|
||||||
|
##
|
||||||
|
## As a special rule, when the value of ``decodePlus`` is true, ``'+'``
|
||||||
|
## characters are converted to a space.
|
||||||
proc handleHexChar(c: char, x: var int) {.inline.} =
|
proc handleHexChar(c: char, x: var int) {.inline.} =
|
||||||
case c
|
case c
|
||||||
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
|
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
|
||||||
|
|
@ -84,7 +95,11 @@ proc decodeUrl*(s: string): string =
|
||||||
handleHexChar(s[i+2], x)
|
handleHexChar(s[i+2], x)
|
||||||
inc(i, 2)
|
inc(i, 2)
|
||||||
result[j] = chr(x)
|
result[j] = chr(x)
|
||||||
of '+': result[j] = ' '
|
of '+':
|
||||||
|
if decodePlus:
|
||||||
|
result[j] = ' '
|
||||||
|
else:
|
||||||
|
result[j] = s[i]
|
||||||
else: result[j] = s[i]
|
else: result[j] = s[i]
|
||||||
inc(i)
|
inc(i)
|
||||||
inc(j)
|
inc(j)
|
||||||
|
|
@ -370,6 +385,9 @@ when isMainModule:
|
||||||
const test1 = "abc\L+def xyz"
|
const test1 = "abc\L+def xyz"
|
||||||
doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz"
|
doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz"
|
||||||
doAssert decodeUrl(encodeUrl(test1)) == test1
|
doAssert decodeUrl(encodeUrl(test1)) == test1
|
||||||
|
doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz"
|
||||||
|
doAssert decodeUrl(encodeUrl(test1, false), false) == test1
|
||||||
|
doAssert decodeUrl(encodeUrl(test1)) == test1
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let str = "http://localhost"
|
let str = "http://localhost"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue