-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 0af9c89
Showing
5 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.pyc | ||
*.pyo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
### Nuri | ||
|
||
A happy little uri parsing and handy dandy little helper. | ||
|
||
**Need a little help with query params?** | ||
|
||
myuri = Uri("http://example.com/path/page") | ||
myuri.query_params["id"] = 1239 | ||
str(myuri) == "http://example.com/path/page?id=1239" |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import unittest | ||
from uri import Uri | ||
|
||
class GeneralTest(unittest.TestCase): | ||
def testClassInstatiates(self): | ||
myuri = Uri() | ||
self.assertIsNotNone(myuri) | ||
|
||
class EasyHttpsUriParseTest(unittest.TestCase): | ||
def setUp(self): | ||
self.myuri = Uri("https://www.example.com/subdir/file.html") | ||
|
||
def testUriScheme(self): | ||
self.assertEqual("https", self.myuri.scheme) | ||
|
||
def testUriHost(self): | ||
self.assertEqual("www.example.com", self.myuri.host) | ||
|
||
def testUriPath(self): | ||
self.assertEqual("/subdir/file.html", self.myuri.path) | ||
|
||
def testUriQueryParams(self): | ||
self.assertEqual({}, self.myuri.query_params) | ||
|
||
|
||
class EasyHttpUriParseTest(unittest.TestCase): | ||
def setUp(self): | ||
self.myuri = Uri("http://sub.example.com/directory/path") | ||
|
||
def testUriScheme(self): | ||
self.assertEqual("http", self.myuri.scheme) | ||
|
||
def testUriHost(self): | ||
self.assertEqual("sub.example.com", self.myuri.host) | ||
|
||
def testUriPath(self): | ||
self.assertEqual("/directory/path", self.myuri.path) | ||
|
||
def testUriQueryParams(self): | ||
self.assertEqual({}, self.myuri.query_params) | ||
|
||
class EasyFileUriParseTest(unittest.TestCase): | ||
def setUp(self): | ||
self.myuri = Uri("file:///etc/nginx/sites-available/default") | ||
|
||
def testUriScheme(self): | ||
self.assertEqual("file", self.myuri.scheme) | ||
|
||
def testUriHost(self): | ||
self.assertEqual("", self.myuri.host) | ||
|
||
def testUriPath(self): | ||
self.assertEqual("/etc/nginx/sites-available/default", self.myuri.path) | ||
|
||
def testUriQueryParams(self): | ||
self.assertEqual({}, self.myuri.query_params) | ||
|
||
class TrixyUriParseTest(unittest.TestCase): | ||
def testEmptyUri(self): | ||
myuri = Uri("") | ||
self.assertIsNotNone(myuri) | ||
self.assertIsNone(myuri.scheme) | ||
self.assertIsNone(myuri.authority) | ||
self.assertIsNone(myuri.host) | ||
self.assertIsNone(myuri.path) | ||
self.assertEqual({}, myuri.query_params) | ||
|
||
def testJustPathUri(self): | ||
myuri = Uri("path.html") | ||
self.assertIsNone(myuri.scheme) | ||
self.assertIsNone(myuri.authority) | ||
self.assertIsNone(myuri.host) | ||
self.assertEqual("path.html", myuri.path) | ||
self.assertEqual({}, myuri.query_params) | ||
|
||
def testUrnUri(self): | ||
myuri = Uri("urn:path:to:nowhere") | ||
self.assertEqual(myuri.scheme, "urn") | ||
self.assertIsNone(myuri.authority) | ||
self.assertIsNone(myuri.host) | ||
self.assertEqual(myuri.path, "path:to:nowhere") | ||
self.assertEqual(myuri.query_params, {}) | ||
|
||
def testPathParsing(self): | ||
self.assertEqual(Uri("http://bob/abc?q=1").path, "/abc") | ||
self.assertEqual(Uri("http://bob/zyx#thing").path, "/zyx") | ||
self.assertEqual(Uri("urn:/etc/path?abc#thing").path, "/etc/path") | ||
|
||
def testIpHostParsing(self): | ||
self.assertEqual(Uri("http://10.0.0.1/bob.html").host, "10.0.0.1") | ||
self.assertEqual(Uri("http://[::1]/bob.html").host, "[::1]") | ||
|
||
class UriStringTest(unittest.TestCase): | ||
def testHttpToString(self): | ||
myuri = Uri("http://example.com/path/to/file.html") | ||
self.assertEqual(str(myuri), "http://example.com/path/to/file.html") | ||
|
||
def testHttpWithParamsToString(self): | ||
myuri = Uri("http://example.com/path/to/file.html") | ||
myuri.query_params["test"] = "bob" | ||
self.assertEqual(str(myuri), "http://example.com/path/to/file.html?test=bob") | ||
myuri.query_params["id"] = 1234 | ||
self.assertEqual(str(myuri), "http://example.com/path/to/file.html?test=bob&id=1234") | ||
|
||
# Run the unit tests if called directly | ||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
|
||
class Uri: | ||
""" | ||
A class for dealing with Uniform Resource Indicators defined by rfc3986 | ||
""" | ||
scheme = None; | ||
authority = None; | ||
host = None; | ||
path = None; | ||
query_params = {}; | ||
|
||
def __init__(self, uri=None): | ||
if uri != None: | ||
self.parse(uri) | ||
|
||
def parse(self, uri): | ||
"""Parse the provided uri into the various components of a uri""" | ||
|
||
scheme_range = None | ||
# Grab the scheme (the part before the colon) | ||
if uri.find(":") >= 0: | ||
scheme_idx = uri.find(':') | ||
scheme_range = (0, scheme_idx,) | ||
self.scheme = uri[scheme_range[0]:scheme_range[1]] | ||
|
||
# Grab the authority, if we have one | ||
authority_range = None | ||
if uri.find("//") >= 0: | ||
authority_start_idx = uri.find("//") + 2 # account for the // characters | ||
authority_end_idx = -1 | ||
# we have an authority, look for and ending (/, ?, #) | ||
if uri.find('/', authority_start_idx) >= 0: | ||
authority_end_idx = uri.find('/', authority_start_idx) | ||
elif uri.find('?', authority_start_idx) >= 0: | ||
authority_end_idx = uri.find('?', authority_start_idx) | ||
elif uri.find('#', authority_start_idx) >= 0: | ||
authority_end_idx = uri.find('#', authority_start_idx) | ||
else: | ||
authority_end_idx = len(uri) | ||
|
||
authority_range = (authority_start_idx, authority_end_idx,) | ||
self.authority = uri[authority_start_idx:authority_end_idx] | ||
|
||
# TODO: parse authority into user-spec, host, port - converting this properly | ||
# requires being able to parse domain, IPv4, IPv6, users, ports | ||
# authority = [ userinfo "@" ] host [ ":" port ] | ||
# userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) | ||
# host = IP-literal / IPv4address / reg-name | ||
# port = *DIGIT | ||
self.host = self.authority | ||
|
||
# Parse out the path | ||
path_range = None | ||
|
||
# Check for authority, then scheme (authority always comes after scheme) | ||
path_start_idx = -1 | ||
if authority_range != None: | ||
path_start_idx = authority_range[1] | ||
elif authority_range == None and scheme_range != None: | ||
path_start_idx = scheme_range[1] + 1 # account for the : | ||
# Check for naked path | ||
elif scheme_range == None and authority_range == None: | ||
path_start_idx = 0 | ||
|
||
# Determine the path range if we have a place to start | ||
if path_start_idx >= 0: | ||
# Calculate range | ||
if uri.find('?', path_start_idx) >= 0: | ||
path_range = (path_start_idx, uri.find('?', path_start_idx),) | ||
elif uri.find('#', path_start_idx) >= 0: | ||
path_range = (path_start_idx, uri.find('#', path_start_idx),) | ||
else: | ||
path_range = (path_start_idx, len(uri),) | ||
|
||
# Grab the path if we have a range to work with | ||
if path_range != None and path_range[0] != path_range[1]: | ||
self.path = uri[path_range[0]:path_range[1]] | ||
|
||
|
||
|
||
def __str__(self): | ||
uri_components = [] | ||
if self.scheme != None: | ||
uri_components.append(self.scheme) | ||
uri_components.append(':') | ||
if self.authority != None: | ||
uri_components.append('//') | ||
uri_components.append(self.authority) | ||
if self.path != None: | ||
uri_components.append(self.path) | ||
|
||
query_indicated = False | ||
for k,v in self.query_params.iteritems(): | ||
if not query_indicated: | ||
uri_components.append('?') | ||
query_indicated = True | ||
else: | ||
uri_components.append('&') | ||
uri_components.append(str(k)) | ||
uri_components.append('=') | ||
uri_components.append(str(v)) # TODO: URL Encode | ||
return ''.join(uri_components) | ||
|
||
|