summary refs log tree commit diff stats
path: root/lib/pure/uri.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/uri.nim')
-rw-r--r--lib/pure/uri.nim48
1 files changed, 48 insertions, 0 deletions
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index 164a57ecf..a651530c3 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -47,6 +47,49 @@ proc add*(url: var Url, a: Url) {.deprecated.} =
   url = url / a
 {.pop.}
 
+proc encodeUrl*(s: string): string =
+  ## Encodes a value to be HTTP safe: This means that characters in the set
+  ## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result,
+  ## a space is converted to ``'+'`` and every other character is encoded as
+  ## ``'%xx'`` where ``xx`` denotes its hexadecimal value.
+  result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars
+  for i in 0..s.len-1:
+    case s[i]
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
+    of ' ': add(result, '+')
+    else:
+      add(result, '%')
+      add(result, toHex(ord(s[i]), 2))
+      
+proc decodeUrl*(s: string): string =
+  ## Decodes a value from its HTTP representation: This means that a ``'+'``
+  ## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
+  ## value) is converted to the character with ordinal number ``xx``, and
+  ## and every other character is carried over.
+  proc handleHexChar(c: char, x: var int) {.inline.} =
+    case c
+    of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
+    of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
+    of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
+    else: assert(false)
+    
+  result = newString(s.len)
+  var i = 0
+  var j = 0
+  while i < s.len:
+    case s[i]
+    of '%':
+      var x = 0
+      handleHexChar(s[i+1], x)
+      handleHexChar(s[i+2], x)
+      inc(i, 2)
+      result[j] = chr(x)
+    of '+': result[j] = ' '
+    else: result[j] = s[i]
+    inc(i)
+    inc(j)
+  setLen(result, j)
+
 proc parseAuthority(authority: string, result: var Uri) =
   var i = 0
   var inPort = false
@@ -328,6 +371,11 @@ proc `$`*(u: Uri): string =
 
 when isMainModule:
   block:
+    const test1 = "abc\L+def xyz"
+    doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz"
+    doAssert decodeUrl(encodeUrl(test1)) == test1
+    
+  block:
     let str = "http://localhost"
     let test = parseUri(str)
     doAssert test.path == ""