Skip to content

Commit

Permalink
Merge pr '#185' of ltvolks into feature/wildcardMIMEAccept
Browse files Browse the repository at this point in the history
  • Loading branch information
digitalresistor committed Jan 29, 2016
2 parents 5200265 + e51a608 commit 065cf9a
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 12 deletions.
64 changes: 63 additions & 1 deletion tests/test_acceptparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,69 @@ def test_match():
assert mimeaccept._match('image/*', 'image/jpg')
assert mimeaccept._match('*/*', 'image/jpg')
assert not mimeaccept._match('text/html', 'image/jpg')
assert_raises(ValueError, mimeaccept._match, 'image/jpg', '*/*')

mismatches = [
('B/b', 'A/a'),
('B/b', 'B/a'),
('B/b', 'A/b'),
('A/a', 'B/b'),
('B/a', 'B/b'),
('A/b', 'B/b')
]
for mask, offer in mismatches:
assert not mimeaccept._match(mask, offer)


def test_wildcard_matching():
"""
Wildcard matching forces the match to take place against the type
or subtype of the mask and offer (depending on where the wildcard
matches)
"""
mimeaccept = MIMEAccept('type/subtype')
matches = [
('*/*', '*/*'),
('*/*', 'A/*'),
('*/*', '*/a'),
('*/*', 'A/a'),
('A/*', '*/*'),
('A/*', 'A/*'),
('A/*', '*/a'),
('A/*', 'A/a'),
('*/a', '*/*'),
('*/a', 'A/*'),
('*/a', '*/a'),
('*/a', 'A/a'),
('A/a', '*/*'),
('A/a', 'A/*'),
('A/a', '*/a'),
('A/a', 'A/a'),
# Offers might not contain a subtype
('*/*', '*'),
('A/*', '*'),
('*/a', '*')]
for mask, offer in matches:
assert mimeaccept._match(mask, offer)
# Test malformed mask and offer variants where either is missing
# a type or subtype
assert mimeaccept._match('A', offer)
assert mimeaccept._match(mask, 'a')

mismatches = [
('B/b', 'A/*'),
('B/*', 'A/a'),
('B/*', 'A/*'),
('*/b', '*/a')]
for mask, offer in mismatches:
assert not mimeaccept._match(mask, offer)

def test_mimeaccept_contains():
mimeaccept = MIMEAccept('A/a, B/b, C/c')
assert 'A/a' in mimeaccept
assert 'A/*' in mimeaccept
assert '*/a' in mimeaccept
assert not 'A/b' in mimeaccept
assert not 'B/a' in mimeaccept

def test_accept_json():
mimeaccept = MIMEAccept('text/html, *; q=.2, */*; q=.2')
Expand Down
1 change: 0 additions & 1 deletion tests/test_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -2472,7 +2472,6 @@ def test_accept_best_match(self):
self.assertTrue(not self._blankOne('/', headers={'Accept': ''}).accept)
req = self._blankOne('/', headers={'Accept':'text/plain'})
self.assertTrue(req.accept)
self.assertRaises(ValueError, req.accept.best_match, ['*/*'])
req = self._blankOne('/', accept=['*/*','text/*'])
self.assertEqual(
req.accept.best_match(['application/x-foo', 'text/plain']),
Expand Down
62 changes: 52 additions & 10 deletions webob/acceptparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ class MIMEAccept(Accept):
def parse(value):
for mask, q in Accept.parse(value):
try:
mask_major, mask_minor = map(lambda x: x.lower(), mask.split('/'))
mask_major, mask_minor = [x.lower() for x in mask.split('/')]
except ValueError:
continue
if mask_major == '*' and mask_minor != '*':
Expand All @@ -296,20 +296,62 @@ def accept_html(self):

accepts_html = property(accept_html) # note the plural


def _match(self, mask, offer):
"""
Check if the offer is covered by the mask
``offer`` may contain wildcards to facilitate checking if a
``mask`` would match a 'permissive' offer.
Wildcard matching forces the match to take place against the
type or subtype of the mask and offer (depending on where
the wildcard matches)
"""
_check_offer(offer)
if '*' not in mask:
return offer.lower() == mask.lower()
elif mask == '*/*':
# Match if comparisons are the same or either is a complete wildcard
if (mask.lower() == offer.lower() or
'*/*' in (mask, offer) or
'*' == offer):
return True
else:
assert mask.endswith('/*')
mask_major = mask[:-2].lower()
offer_major = offer.split('/', 1)[0].lower()
return offer_major == mask_major

# Set mask type with wildcard subtype for malformed masks
try:
mask_type, mask_subtype = [x.lower() for x in mask.split('/')]
except ValueError:
mask_type = mask
mask_subtype = '*'

# Set offer type with wildcard subtype for malformed offers
try:
offer_type, offer_subtype = [x.lower() for x in offer.split('/')]
except ValueError:
offer_type = offer
offer_subtype = '*'

if mask_subtype == '*':
# match on type only
if offer_type == '*':
return True
else:
return mask_type.lower() == offer_type.lower()

if mask_type == '*':
# match on subtype only
if offer_subtype == '*':
return True
else:
return mask_subtype.lower() == offer_subtype.lower()

if offer_subtype == '*':
# match on type only
return mask_type.lower() == offer_type.lower()

if offer_type == '*':
# match on subtype only
return mask_subtype.lower() == offer_subtype.lower()

return offer.lower() == mask.lower()



class MIMENilAccept(NilAccept):
Expand Down

0 comments on commit 065cf9a

Please sign in to comment.