feat(API): Routes now treat paths with a trailing slash as identical.

Implements #48
This commit is contained in:
Kurt Griffiths
2013-03-01 17:02:30 -05:00
parent 074beaec24
commit a9f8208543
3 changed files with 25 additions and 10 deletions

View File

@@ -22,7 +22,8 @@ This requires some discipline on the part of the developer.
* URI template and query string field names must include only ASCII a-z, A-Z, and the underscore '_' character. Try it; you'll like it. This simplifies parsing and helps speed things up a bit.
* Query params must have a value. In other words, 'foo' or 'foo=' will result in the parameter being ignored.
* If the WSGI server passes an empty path, Falcon will force it to '/', so you don't have to test for the empty string in your app.
* If you are hosting multiple apps with a single WSGI server, the SCRIPT_NAME variable can read from req.app
* The routes '/foo/bar' and '/foo/bar/' are identical as far as Falcon is concerned. Requests coming in for either will be sent to the same resource.
* If you are hosting multiple apps with a single WSGI server, the SCRIPT_NAME variable can be read from req.app
* If you have several headers to set, consider using set_headers to avoid function call overhead
* Don't set content-length. It will only be overridden.
* The order in which header fields are sent in the response is undefined. Headers are not grouped according to the recommendation in [RFC 2616](http://tools.ietf.org/html/rfc2616#section-4.2) in order to generate responses as quickly as possible.

View File

@@ -143,11 +143,13 @@ def compile_uri_template(template=None):
if not template:
template = '/'
elif template != '/' and template.endswith('/'):
template = template[:-1]
# Convert Level 1 var patterns to equivalent named regex groups
escaped = re.sub(r'([\.\(\)\[\]\?\*\+\^\|])', r'\.', template)
pattern = re.sub(r'{([a-zA-Z][a-zA-Z_]*)}', r'(?P<\1>[^/]+)', escaped)
pattern = r'\A' + pattern + r'\Z'
pattern = r'\A' + pattern + r'/?\Z'
return re.compile(pattern, re.IGNORECASE)

View File

@@ -68,17 +68,29 @@ class TestUriTemplates(testing.TestSuite):
self.assertEquals(req.get_param('id'), None)
def test_single_trailing_slash(self):
resource = IDResource()
self.api.add_route('/widgets/{id}/', resource)
resource1 = IDResource()
self.api.add_route('/1/{id}/', resource1)
self.simulate_request('/widgets/123')
self.assertFalse(resource.called)
self.simulate_request('/1/123')
self.assertTrue(resource1.called)
self.assertEquals(resource1.id, '123')
self.assertEquals(resource1.name, None)
self.simulate_request('/widgets/123/')
self.assertTrue(resource.called)
resource2 = IDResource()
self.api.add_route('/2/{id}/', resource2)
self.assertEquals(resource.id, '123')
self.assertEquals(resource.name, None)
self.simulate_request('/2/123/')
self.assertTrue(resource2.called)
self.assertEquals(resource2.id, '123')
self.assertEquals(resource2.name, None)
resource3 = IDResource()
self.api.add_route('/3/{id}', resource3)
self.simulate_request('/3/123/')
self.assertTrue(resource3.called)
self.assertEquals(resource3.id, '123')
self.assertEquals(resource3.name, None)
def test_multiple(self):
resource = IDResource()