Accept valid Accept headers in swob.
"Accept: application/xml; charset=UTF-8" is totally valid, and has an implicit q (quality) value of 1.0, just the same as "Accept: text/xml" does. Also, you can say things like: Accept: text/xml; charset=UTF-8; q=0.9; anglebrackets="are awesome" with as many arbitrary extensions as you want. See RFC 2616 sections 14.1 Accept and 2.2 Basic Rules for details. Fixes bug 1202453. Change-Id: I18e6d0ee3fd6f9d889275ee8335e711c729b7171
This commit is contained in:
parent
c9de9f2b8d
commit
91e7e876b5
|
@ -603,9 +603,17 @@ class Accept(object):
|
|||
|
||||
:param headerval: value of the header as a str
|
||||
"""
|
||||
token = r'[^()<>@,;:\"/\[\]?={}\x00-\x20\x7f]+' # RFC 2616 2.2
|
||||
acc_pattern = re.compile(r'^\s*(' + token + r')/(' + token +
|
||||
r')(;\s*q=([\d.]+))?\s*$')
|
||||
|
||||
# RFC 2616 section 2.2
|
||||
token = r'[^()<>@,;:\"/\[\]?={}\x00-\x20\x7f]+'
|
||||
qdtext = r'[^"]'
|
||||
quoted_pair = r'(?:\\.)'
|
||||
quoted_string = r'"(?:' + qdtext + r'|' + quoted_pair + r')*"'
|
||||
extension = (r'(?:\s*;\s*(?:' + token + r")\s*=\s*" + r'(?:' + token +
|
||||
r'|' + quoted_string + r'))')
|
||||
acc = (r'^\s*(' + token + r')/(' + token +
|
||||
r')(' + extension + r'*?\s*)$')
|
||||
acc_pattern = re.compile(acc)
|
||||
|
||||
def __init__(self, headerval):
|
||||
self.headerval = headerval
|
||||
|
@ -618,8 +626,22 @@ class Accept(object):
|
|||
type_parms = self.acc_pattern.findall(typ)
|
||||
if not type_parms:
|
||||
raise ValueError('Invalid accept header')
|
||||
typ, subtype, parms, quality = type_parms[0]
|
||||
quality = float(quality or '1.0')
|
||||
typ, subtype, parms = type_parms[0]
|
||||
parms = [p.strip() for p in parms.split(';') if p.strip()]
|
||||
|
||||
seen_q_already = False
|
||||
quality = 1.0
|
||||
|
||||
for parm in parms:
|
||||
name, value = parm.split('=')
|
||||
name = name.strip()
|
||||
value = value.strip()
|
||||
if name == 'q':
|
||||
if seen_q_already:
|
||||
raise ValueError('Multiple "q" params')
|
||||
seen_q_already = True
|
||||
quality = float(value)
|
||||
|
||||
pattern = '^' + \
|
||||
(self.token if typ == '*' else re.escape(typ)) + '/' + \
|
||||
(self.token if subtype == '*' else re.escape(subtype)) + '$'
|
||||
|
|
|
@ -261,7 +261,10 @@ class TestAccept(unittest.TestCase):
|
|||
|
||||
def test_accept_xml(self):
|
||||
for accept in ('application/xml', 'application/xml;q=1.0,*/*;q=0.9',
|
||||
'*/*;q=0.9,application/xml;q=1.0'):
|
||||
'*/*;q=0.9,application/xml;q=1.0',
|
||||
'application/xml;charset=UTF-8',
|
||||
'application/xml;charset=UTF-8;qws="quoted with space"',
|
||||
'application/xml; q=0.99 ; qws="quoted with space"'):
|
||||
acc = swift.common.swob.Accept(accept)
|
||||
match = acc.best_match(['text/plain', 'application/xml',
|
||||
'text/xml'])
|
||||
|
@ -270,7 +273,10 @@ class TestAccept(unittest.TestCase):
|
|||
def test_accept_invalid(self):
|
||||
for accept in ('*', 'text/plain,,', 'some stuff',
|
||||
'application/xml;q=1.0;q=1.1', 'text/plain,*',
|
||||
'text /plain', 'text\x7f/plain'):
|
||||
'text /plain', 'text\x7f/plain',
|
||||
'text/plain;a=b=c',
|
||||
'text/plain;q=1;q=2',
|
||||
'text/plain; ubq="unbalanced " quotes"'):
|
||||
acc = swift.common.swob.Accept(accept)
|
||||
match = acc.best_match(['text/plain', 'application/xml',
|
||||
'text/xml'])
|
||||
|
@ -280,6 +286,7 @@ class TestAccept(unittest.TestCase):
|
|||
acc = swift.common.swob.Accept("application/json")
|
||||
self.assertEquals(repr(acc), "application/json")
|
||||
|
||||
|
||||
class TestRequest(unittest.TestCase):
|
||||
def test_blank(self):
|
||||
req = swift.common.swob.Request.blank(
|
||||
|
|
Loading…
Reference in New Issue