uri.nim: don't rely on zero termination
This commit is contained in:
parent
203d833688
commit
f4c21305a9
1 changed files with 18 additions and 21 deletions
|
|
@ -60,7 +60,7 @@ proc encodeUrl*(s: string): string =
|
||||||
else:
|
else:
|
||||||
add(result, '%')
|
add(result, '%')
|
||||||
add(result, toHex(ord(s[i]), 2))
|
add(result, toHex(ord(s[i]), 2))
|
||||||
|
|
||||||
proc decodeUrl*(s: string): string =
|
proc decodeUrl*(s: string): string =
|
||||||
## Decodes a value from its HTTP representation: This means that a ``'+'``
|
## Decodes a value from its HTTP representation: This means that a ``'+'``
|
||||||
## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
|
## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
|
||||||
|
|
@ -72,7 +72,7 @@ proc decodeUrl*(s: string): string =
|
||||||
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)
|
||||||
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)
|
else: assert(false)
|
||||||
|
|
||||||
result = newString(s.len)
|
result = newString(s.len)
|
||||||
var i = 0
|
var i = 0
|
||||||
var j = 0
|
var j = 0
|
||||||
|
|
@ -94,7 +94,7 @@ proc parseAuthority(authority: string, result: var Uri) =
|
||||||
var i = 0
|
var i = 0
|
||||||
var inPort = false
|
var inPort = false
|
||||||
var inIPv6 = false
|
var inIPv6 = false
|
||||||
while true:
|
while i < authority.len:
|
||||||
case authority[i]
|
case authority[i]
|
||||||
of '@':
|
of '@':
|
||||||
swap result.password, result.port
|
swap result.password, result.port
|
||||||
|
|
@ -111,7 +111,6 @@ proc parseAuthority(authority: string, result: var Uri) =
|
||||||
inIPv6 = true
|
inIPv6 = true
|
||||||
of ']':
|
of ']':
|
||||||
inIPv6 = false
|
inIPv6 = false
|
||||||
of '\0': break
|
|
||||||
else:
|
else:
|
||||||
if inPort:
|
if inPort:
|
||||||
result.port.add(authority[i])
|
result.port.add(authority[i])
|
||||||
|
|
@ -128,11 +127,11 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
|
||||||
parseAuthority(result.path, result)
|
parseAuthority(result.path, result)
|
||||||
result.path.setLen(0)
|
result.path.setLen(0)
|
||||||
|
|
||||||
if uri[i] == '?':
|
if i < uri.len and uri[i] == '?':
|
||||||
i.inc # Skip '?'
|
i.inc # Skip '?'
|
||||||
i.inc parseUntil(uri, result.query, {'#'}, i)
|
i.inc parseUntil(uri, result.query, {'#'}, i)
|
||||||
|
|
||||||
if uri[i] == '#':
|
if i < uri.len and uri[i] == '#':
|
||||||
i.inc # Skip '#'
|
i.inc # Skip '#'
|
||||||
i.inc parseUntil(uri, result.anchor, {}, i)
|
i.inc parseUntil(uri, result.anchor, {}, i)
|
||||||
|
|
||||||
|
|
@ -156,7 +155,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||||
|
|
||||||
# Check if this is a reference URI (relative URI)
|
# Check if this is a reference URI (relative URI)
|
||||||
let doubleSlash = uri.len > 1 and uri[1] == '/'
|
let doubleSlash = uri.len > 1 and uri[1] == '/'
|
||||||
if uri[i] == '/':
|
if i < uri.len and uri[i] == '/':
|
||||||
# Make sure ``uri`` doesn't begin with '//'.
|
# Make sure ``uri`` doesn't begin with '//'.
|
||||||
if not doubleSlash:
|
if not doubleSlash:
|
||||||
parsePath(uri, i, result)
|
parsePath(uri, i, result)
|
||||||
|
|
@ -164,7 +163,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||||
|
|
||||||
# Scheme
|
# Scheme
|
||||||
i.inc parseWhile(uri, result.scheme, Letters + Digits + {'+', '-', '.'}, i)
|
i.inc parseWhile(uri, result.scheme, Letters + Digits + {'+', '-', '.'}, i)
|
||||||
if uri[i] != ':' and not doubleSlash:
|
if (i >= uri.len or uri[i] != ':') and not doubleSlash:
|
||||||
# Assume this is a reference URI (relative URI)
|
# Assume this is a reference URI (relative URI)
|
||||||
i = 0
|
i = 0
|
||||||
result.scheme.setLen(0)
|
result.scheme.setLen(0)
|
||||||
|
|
@ -174,7 +173,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||||
i.inc # Skip ':'
|
i.inc # Skip ':'
|
||||||
|
|
||||||
# Authority
|
# Authority
|
||||||
if uri[i] == '/' and uri[i+1] == '/':
|
if i+1 < uri.len and uri[i] == '/' and uri[i+1] == '/':
|
||||||
i.inc(2) # Skip //
|
i.inc(2) # Skip //
|
||||||
var authority = ""
|
var authority = ""
|
||||||
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
|
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
|
||||||
|
|
@ -197,13 +196,13 @@ proc removeDotSegments(path: string): string =
|
||||||
let endsWithSlash = path[path.len-1] == '/'
|
let endsWithSlash = path[path.len-1] == '/'
|
||||||
var i = 0
|
var i = 0
|
||||||
var currentSegment = ""
|
var currentSegment = ""
|
||||||
while true:
|
while i < path.len:
|
||||||
case path[i]
|
case path[i]
|
||||||
of '/':
|
of '/':
|
||||||
collection.add(currentSegment)
|
collection.add(currentSegment)
|
||||||
currentSegment = ""
|
currentSegment = ""
|
||||||
of '.':
|
of '.':
|
||||||
if path[i+1] == '.' and path[i+2] == '/':
|
if i+2 < path.len and path[i+1] == '.' and path[i+2] == '/':
|
||||||
if collection.len > 0:
|
if collection.len > 0:
|
||||||
discard collection.pop()
|
discard collection.pop()
|
||||||
i.inc 3
|
i.inc 3
|
||||||
|
|
@ -212,13 +211,11 @@ proc removeDotSegments(path: string): string =
|
||||||
i.inc 2
|
i.inc 2
|
||||||
continue
|
continue
|
||||||
currentSegment.add path[i]
|
currentSegment.add path[i]
|
||||||
of '\0':
|
|
||||||
if currentSegment != "":
|
|
||||||
collection.add currentSegment
|
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
currentSegment.add path[i]
|
currentSegment.add path[i]
|
||||||
i.inc
|
i.inc
|
||||||
|
if currentSegment != "":
|
||||||
|
collection.add currentSegment
|
||||||
|
|
||||||
result = collection.join("/")
|
result = collection.join("/")
|
||||||
if endsWithSlash: result.add '/'
|
if endsWithSlash: result.add '/'
|
||||||
|
|
@ -320,18 +317,18 @@ proc `/`*(x: Uri, path: string): Uri =
|
||||||
result = x
|
result = x
|
||||||
|
|
||||||
if result.path.len == 0:
|
if result.path.len == 0:
|
||||||
if path[0] != '/':
|
if path.len == 0 or path[0] != '/':
|
||||||
result.path = "/"
|
result.path = "/"
|
||||||
result.path.add(path)
|
result.path.add(path)
|
||||||
return
|
return
|
||||||
|
|
||||||
if result.path[result.path.len-1] == '/':
|
if result.path.len > 0 and result.path[result.path.len-1] == '/':
|
||||||
if path[0] == '/':
|
if path.len > 0 and path[0] == '/':
|
||||||
result.path.add(path[1 .. path.len-1])
|
result.path.add(path[1 .. path.len-1])
|
||||||
else:
|
else:
|
||||||
result.path.add(path)
|
result.path.add(path)
|
||||||
else:
|
else:
|
||||||
if path[0] != '/':
|
if path.len == 0 or path[0] != '/':
|
||||||
result.path.add '/'
|
result.path.add '/'
|
||||||
result.path.add(path)
|
result.path.add(path)
|
||||||
|
|
||||||
|
|
@ -373,7 +370,7 @@ 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
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let str = "http://localhost"
|
let str = "http://localhost"
|
||||||
let test = parseUri(str)
|
let test = parseUri(str)
|
||||||
|
|
@ -464,7 +461,7 @@ when isMainModule:
|
||||||
doAssert test.hostname == "github.com"
|
doAssert test.hostname == "github.com"
|
||||||
doAssert test.port == "dom96"
|
doAssert test.port == "dom96"
|
||||||
doAssert test.path == "/packages"
|
doAssert test.path == "/packages"
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let str = "file:///foo/bar/baz.txt"
|
let str = "file:///foo/bar/baz.txt"
|
||||||
let test = parseUri(str)
|
let test = parseUri(str)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue