Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/rest_framework/utils/mediatypes.py: 80%
35 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2Handling of media types, as found in HTTP Content-Type and Accept headers.
4See https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
5"""
6from django.http.multipartparser import parse_header
8from rest_framework import HTTP_HEADER_ENCODING
11def media_type_matches(lhs, rhs):
12 """
13 Returns ``True`` if the media type in the first argument <= the
14 media type in the second argument. The media types are strings
15 as described by the HTTP spec.
17 Valid media type strings include:
19 'application/json; indent=4'
20 'application/json'
21 'text/*'
22 '*/*'
23 """
24 lhs = _MediaType(lhs)
25 rhs = _MediaType(rhs)
26 return lhs.match(rhs)
29def order_by_precedence(media_type_lst):
30 """
31 Returns a list of sets of media type strings, ordered by precedence.
32 Precedence is determined by how specific a media type is:
34 3. 'type/subtype; param=val'
35 2. 'type/subtype'
36 1. 'type/*'
37 0. '*/*'
38 """
39 ret = [set(), set(), set(), set()]
40 for media_type in media_type_lst:
41 precedence = _MediaType(media_type).precedence
42 ret[3 - precedence].add(media_type)
43 return [media_types for media_types in ret if media_types]
46class _MediaType:
47 def __init__(self, media_type_str):
48 self.orig = '' if (media_type_str is None) else media_type_str
49 self.full_type, self.params = parse_header(self.orig.encode(HTTP_HEADER_ENCODING))
50 self.main_type, sep, self.sub_type = self.full_type.partition('/')
52 def match(self, other):
53 """Return true if this MediaType satisfies the given MediaType."""
54 for key in self.params: 54 ↛ 55line 54 didn't jump to line 55, because the loop on line 54 never started
55 if key != 'q' and other.params.get(key, None) != self.params.get(key, None):
56 return False
58 if self.sub_type != '*' and other.sub_type != '*' and other.sub_type != self.sub_type:
59 return False
61 if self.main_type != '*' and other.main_type != '*' and other.main_type != self.main_type: 61 ↛ 62line 61 didn't jump to line 62, because the condition on line 61 was never true
62 return False
64 return True
66 @property
67 def precedence(self):
68 """
69 Return a precedence level from 0-3 for the media type given how specific it is.
70 """
71 if self.main_type == '*':
72 return 0
73 elif self.sub_type == '*': 73 ↛ 74line 73 didn't jump to line 74, because the condition on line 73 was never true
74 return 1
75 elif not self.params or list(self.params) == ['q']: 75 ↛ 77line 75 didn't jump to line 77, because the condition on line 75 was never false
76 return 2
77 return 3
79 def __str__(self):
80 ret = "%s/%s" % (self.main_type, self.sub_type)
81 for key, val in self.params.items():
82 ret += "; %s=%s" % (key, val.decode('ascii'))
83 return ret