diff options
-rw-r--r-- | lib/pure/parseurl.nim | 110 | ||||
-rw-r--r-- | lib/pure/uri.nim | 37 | ||||
-rw-r--r-- | lib/pure/url.nim | 213 |
3 files changed, 147 insertions, 213 deletions
diff --git a/lib/pure/parseurl.nim b/lib/pure/parseurl.nim new file mode 100644 index 000000000..357d1df0f --- /dev/null +++ b/lib/pure/parseurl.nim @@ -0,0 +1,110 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2014 Dominik Picheta +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Parses & constructs URLs. +## +## **Note**: This module will be deprecated in the future and merged into a +## new ``url`` module. + +import strutils + +type + TUrl* = tuple[ ## represents a *Uniform Resource Locator* (URL) + ## any optional component is "" if it does not exist + scheme, username, password, + hostname, port, path, query, anchor: string] + +proc parseUrl*(url: string): TUrl = + var i = 0 + + var scheme, username, password: string = "" + var hostname, port, path, query, anchor: string = "" + + var temp = "" + + if url[i] != '/': # url isn't a relative path + while True: + # Scheme + if url[i] == ':': + if url[i+1] == '/' and url[i+2] == '/': + scheme = temp + temp.setlen(0) + inc(i, 3) # Skip the // + # Authority(username, password) + if url[i] == '@': + username = temp + let colon = username.find(':') + if colon >= 0: + password = username.substr(colon+1) + username = username.substr(0, colon-1) + temp.setlen(0) + inc(i) #Skip the @ + # hostname(subdomain, domain, port) + if url[i] == '/' or url[i] == '\0': + hostname = temp + let colon = hostname.find(':') + if colon >= 0: + port = hostname.substr(colon+1) + hostname = hostname.substr(0, colon-1) + + temp.setlen(0) + break + + temp.add(url[i]) + inc(i) + + if url[i] == '/': inc(i) # Skip the '/' + # Path + while True: + if url[i] == '?': + path = temp + temp.setlen(0) + if url[i] == '#': + if temp[0] == '?': + query = temp + else: + path = temp + temp.setlen(0) + + if url[i] == '\0': + if temp[0] == '?': + query = temp + elif temp[0] == '#': + anchor = temp + else: + path = temp + break + + temp.add(url[i]) + inc(i) + + return (scheme, username, password, hostname, port, path, query, anchor) + +proc `$`*(u: TUrl): string = + ## turns the URL `u` into its string representation. + result = "" + if u.scheme.len > 0: + result.add(u.scheme) + result.add("://") + if u.username.len > 0: + result.add(u.username) + if u.password.len > 0: + result.add(":") + result.add(u.password) + result.add("@") + result.add(u.hostname) + if u.port.len > 0: + result.add(":") + result.add(u.port) + if u.path.len > 0: + result.add("/") + result.add(u.path) + result.add(u.query) + result.add(u.anchor) + diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim new file mode 100644 index 000000000..ee1226a35 --- /dev/null +++ b/lib/pure/uri.nim @@ -0,0 +1,37 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2014 Dominik Picheta +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## **Note**: This module will be deprecated in the future and merged into a +## new ``url`` module. + +import strutils +type + TUrl* = distinct string + +proc `$`*(url: TUrl): string = return string(url) + +proc `/`*(a, b: TUrl): TUrl = + ## Joins two URLs together, separating them with / if needed. + var urlS = $a + var bS = $b + if urlS == "": return b + if urlS[urlS.len-1] != '/': + urlS.add('/') + if bS[0] == '/': + urlS.add(bS.substr(1)) + else: + urlS.add(bs) + result = TUrl(urlS) + +proc add*(url: var TUrl, a: TUrl) = + ## Appends url to url. + url = url / a + +when isMainModule: + assert($("http://".TUrl / "localhost:5000".TUrl) == "http://localhost:5000") diff --git a/lib/pure/url.nim b/lib/pure/url.nim deleted file mode 100644 index fa7533886..000000000 --- a/lib/pure/url.nim +++ /dev/null @@ -1,213 +0,0 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2014 Dominik Picheta -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Parses & constructs URLs. - -import strutils - -type - TUrl* = tuple[ ## represents a *Uniform Resource Locator* (URL) - ## any optional component is "" if it does not exist - scheme, username, password, - hostname, port, path, query, anchor: string] - - -proc skip(i: var int, skippedChars: string) = - inc(i, skippedChars.len) - -proc readScheme(url: var TUrl, temp: string) = - url.scheme = temp - -proc readAuthority(url: var TUrl, temp: string) = - let colon = temp.find(':') - if colon >= 0: - url.password = temp.substr(colon+1) - url.username = temp.substr(0, colon-1) - -proc readHostAndPort(url: var TUrl, temp: string) = - let colon = temp.find(':') - if colon >= 0: - url.port = temp.substr(colon+1) - url.hostname = temp.substr(0, colon-1) - -proc readUntilPath(self: var TUrl, url: string): int = - var temp = "" - var i = 0 - let relative = url[i] == '/' - if not relative: - while True: - if url[i] == ':': - if url[i+1] == '/' and url[i+2] == '/': - self.readScheme(temp) - i.skip("://") - temp.setlen(0) - if url[i] == '@': - self.readAuthority(temp) - i.skip("@") - temp.setlen(0) - - if url[i] == '/' or url[i] == '\0': - self.readHostAndPort(temp) - temp.setlen(0) - break - - temp.add(url[i]) - inc(i) - - if url[i] == '/': - i.skip("/") - return i - -proc readPath(url: var TUrl, path: string) = - var temp = "" - var i = 0 - while True: - if path[i] == '?': - url.path = temp - temp.setlen(0) - if path[i] == '#': - if temp[0] == '?': - url.query = temp - else: - url.path = temp - temp.setlen(0) - - if path[i] == '\0': - if temp[0] == '?': - url.query = temp - elif temp[0] == '#': - url.anchor = temp - else: - url.path = temp - break - temp.add(path[i]) - inc(i) - -proc parseUrl*(url: string): TUrl = - result.scheme = "" - result.username = "" - result.password = "" - result.hostname = "" - result.port = "" - result.path = "" - result.query = "" - result.anchor = "" - - let lastIndex = result.readUntilPath(url) - let path = url[lastIndex..url.len] - result.readPath(path) - - -proc `$`*(u: TUrl): string = - ## turns the URL `u` into its string representation. - result = "" - if u.scheme.len > 0: - result.add(u.scheme) - result.add("://") - if u.username.len > 0: - result.add(u.username) - if u.password.len > 0: - result.add(":") - result.add(u.password) - result.add("@") - result.add(u.hostname) - if u.port.len > 0: - result.add(":") - result.add(u.port) - if u.path.len > 0: - result.add("/") - result.add(u.path) - result.add(u.query) - result.add(u.anchor) - -proc nvl(a: string, b: string): string = - if a == "": - return b - return a - -proc `/`*(a, b: TUrl): TUrl = - result.scheme = nvl(a.scheme, b.scheme) - result.username = nvl(a.username, b.username) - result.password = nvl(a.password, b.password) - result.hostname = nvl(a.hostname, b.hostname) - result.port = nvl(a.port, b.port) - result.path = nvl(a.path, b.path) - result.query = nvl(a.query, b.query) - result.anchor = nvl(a.anchor, b.anchor) - -when isMainModule: - import unittest - - test "parse full URL": - let url = parseUrl("http://localhost:5000/path?message1=Nimrod&message2=+is+cool!#anchor") - check url.username == "" - check url.password == "" - check url.scheme == "http" - check url.hostname == "localhost" - check url.port == "5000" - check url.path == "path" - check url.query == "?message1=Nimrod&message2=+is+cool!" - check url.anchor == "#anchor" - - test "parse full URL with username and password": - let url = parseUrl("http://username:password@localhost:5000/path?message1=Nimrod&message2=+is+cool!#anchor") - check url.username == "username" - check url.password == "password" - check url.scheme == "http" - check url.hostname == "localhost" - check url.port == "5000" - check url.path == "path" - check url.query == "?message1=Nimrod&message2=+is+cool!" - check url.anchor == "#anchor" - - test "parse URL fragment localhost:5000": - let url = parseUrl("localhost:5000") - check url.username == "" - check url.password == "" - check url.scheme == "" - check url.hostname == "localhost" - check url.port == "5000" - check url.path == "" - check url.query == "" - check url.anchor == "" - - test "parse URL fragment: /path?message1=Nimrod&message2=+is+cool!#anchor": - let url = parseUrl("/path?message1=Nimrod&message2=+is+cool!#anchor") - check url.username == "" - check url.password == "" - check url.scheme == "" - check url.hostname == "" - check url.port == "" - check url.path == "path" - check url.query == "?message1=Nimrod&message2=+is+cool!" - check url.anchor == "#anchor" - - test "parse URL fragment: http://": - let url = parseUrl("http://") - check url.scheme == "http" - check url.username == "" - check url.password == "" - check url.hostname == "" - check url.port == "" - check url.path == "" - check url.query == "" - check url.anchor == "" - - test "url concatenation": - let url1 = parseUrl("http://localhost:5000") - let url2 = parseUrl("/path?message1=Nimrod&message2=+is+cool!#anchor") - let url = url1 / url2 - check url.username == "" - check url.password == "" - check url.scheme == "http" - check url.hostname == "localhost" - check url.port == "5000" - check url.path == "path" - check url.query == "?message1=Nimrod&message2=+is+cool!" - check url.anchor == "#anchor" |