fix: Refine client_accepts

This commit is contained in:
kgriffs
2013-09-11 15:39:53 -05:00
parent dd6568b8bc
commit 21d736ddbe
3 changed files with 23 additions and 43 deletions

View File

@@ -31,8 +31,6 @@ DEFAULT_ERROR_LOG_FORMAT = (u'{0:%Y-%m-%d %H:%M:%S} [FALCON] [ERROR]'
TRUE_STRINGS = ('true', 'True', 'yes')
FALSE_STRINGS = ('false', 'False', 'no')
MEDIA_TYPES_XML = ('application/xml', 'text/xml')
class InvalidHeaderValueError(HTTPBadRequest):
def __init__(self, msg, href=None, href_text=None):
@@ -152,14 +150,13 @@ class Request(object):
@property
def client_accepts_xml(self):
"""Return True if the Accept header indicates XML support."""
return self.client_accepts(MEDIA_TYPES_XML)
return self.client_accepts('application/xml')
def client_accepts(self, media_types):
def client_accepts(self, media_type):
"""Returns the client's preferred media type.
Args:
media_types: One or more media types. May be a single string (
of type str), or an iterable collection of strings.
media_type: Media type to check
Returns:
True IFF the client has indicated in the Accept header that
@@ -170,23 +167,14 @@ class Request(object):
# PERF(kgriffs): Usually the following will be true, so
# try it first.
if isinstance(media_types, str):
if (accept == media_types) or (accept == '*/*'):
return accept
# NOTE(kgriffs): Convert to a collection to be compatible
# with mimeparse.best_matchapplication/xhtml+xml
media_types = (media_types,)
# NOTE(kgriffs): Heuristic to quickly check another common case. If
# accept is a single type, and it is found in media_types verbatim,
# return the media type immediately.
elif accept in media_types:
return accept
if (accept == media_type) or (accept == '*/*'):
return True
# Fall back to full-blown parsing
preferred_type = self.client_prefers(media_types)
return preferred_type is not None
try:
return mimeparse.quality(media_type, accept) != 0.0
except ValueError:
return False
def client_prefers(self, media_types):
"""Returns the client's preferred media type given several choices.

View File

@@ -87,31 +87,27 @@ class TestReqVars(testing.TestBase):
headers = {'Accept': 'application/xml'}
req = Request(testing.create_environ(headers=headers))
self.assertTrue(req.client_accepts('application/xml'))
self.assertTrue(req.client_accepts(['application/xml']))
headers = {'Accept': '*/*'}
req = Request(testing.create_environ(headers=headers))
self.assertTrue(req.client_accepts(['application/xml']))
self.assertTrue(req.client_accepts('application/xml'))
headers = {} # NOTE(kgriffs): Equivalent to '*/*' per RFC
req = Request(testing.create_environ(headers=headers))
self.assertTrue(req.client_accepts('application/xml'))
self.assertTrue(req.client_accepts(['application/xml']))
headers = {'Accept': 'application/json'}
req = Request(testing.create_environ(headers=headers))
self.assertFalse(req.client_accepts(['application/xml']))
self.assertFalse(req.client_accepts('application/xml'))
headers = {'Accept': 'application/xm'}
req = Request(testing.create_environ(headers=headers))
self.assertFalse(req.client_accepts(['application/xml']))
self.assertFalse(req.client_accepts('application/xml'))
headers = {'Accept': 'application/*'}
req = Request(testing.create_environ(headers=headers))
self.assertTrue(req.client_accepts(['application/json']))
self.assertTrue(req.client_accepts(['application/xml']))
self.assertTrue(req.client_accepts(['application/json',
'application/xml']))
self.assertTrue(req.client_accepts('application/json'))
self.assertTrue(req.client_accepts('application/xml'))
headers = {'Accept': 'text/*'}
req = Request(testing.create_environ(headers=headers))
@@ -124,9 +120,6 @@ class TestReqVars(testing.TestBase):
self.assertTrue(req.client_accepts('text/plain'))
self.assertTrue(req.client_accepts('text/csv'))
self.assertTrue(req.client_accepts('application/xhtml+xml'))
self.assertTrue(req.client_accepts(('application/xhtml+xml',
'text/plain',
'text/csv')))
headers = {'Accept': 'text/*; q=0.1, application/xhtml+xml; q=0.5'}
req = Request(testing.create_environ(headers=headers))
@@ -148,15 +141,7 @@ class TestReqVars(testing.TestBase):
self.assertTrue(req.client_accepts_xml)
self.assertFalse(req.client_accepts_json)
headers = {'Accept': 'text/xml'}
req = Request(testing.create_environ(headers=headers))
self.assertTrue(req.client_accepts_xml)
headers = {'Accept': 'text/*'}
req = Request(testing.create_environ(headers=headers))
self.assertTrue(req.client_accepts_xml)
headers = {'Accept': 'text/xml, application/xml'}
headers = {'Accept': 'application/*'}
req = Request(testing.create_environ(headers=headers))
self.assertTrue(req.client_accepts_xml)
@@ -188,6 +173,11 @@ class TestReqVars(testing.TestBase):
preferred_type = req.client_prefers(['application/xhtml+xml'])
self.assertEquals(preferred_type, 'application/xhtml+xml')
headers = {'Accept': '3p12845j;;;asfd;'}
req = Request(testing.create_environ(headers=headers))
preferred_type = req.client_prefers(['application/xhtml+xml'])
self.assertEquals(preferred_type, None)
def test_range(self):
headers = {'Range': '10-'}
req = Request(testing.create_environ(headers=headers))

View File

@@ -83,7 +83,9 @@ def to_query_str(params):
elif v is False:
v = 'false'
elif isinstance(v, list):
v = ','.join([str(i) for i in v])
# PERF(kgriffs): map is faster than list comprehension in
# py26 and py33. No significant different in py27
v = ','.join(map(str, v))
else:
v = str(v)