diff options
Diffstat (limited to 'django')
| -rw-r--r-- | django/http/request.py | 61 |
1 files changed, 44 insertions, 17 deletions
diff --git a/django/http/request.py b/django/http/request.py index 986d4eee89..6438f26268 100644 --- a/django/http/request.py +++ b/django/http/request.py @@ -93,8 +93,12 @@ class HttpRequest: """Return a list of MediaType instances, in order of preference.""" header_value = self.headers.get("Accept", "*/*") return sorted( - (MediaType(token) for token in header_value.split(",") if token.strip()), - key=operator.attrgetter("quality", "specificity"), + ( + media_type + for token in header_value.split(",") + if token.strip() and (media_type := MediaType(token)).quality != 0 + ), + key=operator.attrgetter("specificity", "quality"), reverse=True, ) @@ -102,11 +106,12 @@ class HttpRequest: """ Return the preferred MediaType instance which matches the given media type. """ + media_type = MediaType(media_type) return next( ( accepted_type for accepted_type in self.accepted_types - if accepted_type.match(media_type) + if media_type.match(accepted_type) ), None, ) @@ -689,13 +694,13 @@ class QueryDict(MultiValueDict): class MediaType: def __init__(self, media_type_raw_line): - full_type, self.params = parse_header_parameters( + full_type, self._params = parse_header_parameters( media_type_raw_line if media_type_raw_line else "" ) self.main_type, _, self.sub_type = full_type.partition("/") def __str__(self): - params_str = "".join("; %s=%s" % (k, v) for k, v in self.params.items()) + params_str = "".join("; %s=%s" % (k, v) for k, v in self._params.items()) return "%s%s%s" % ( self.main_type, ("/%s" % self.sub_type) if self.sub_type else "", @@ -705,23 +710,45 @@ class MediaType: def __repr__(self): return "<%s: %s>" % (self.__class__.__qualname__, self) - @property - def is_all_types(self): - return self.main_type == "*" and self.sub_type == "*" + @cached_property + def params(self): + params = self._params.copy() + params.pop("q", None) + return params def match(self, other): - if self.is_all_types: - return True - other = MediaType(other) - return self.main_type == other.main_type and self.sub_type in { - "*", - other.sub_type, - } + if not other: + return False + + if not isinstance(other, MediaType): + other = MediaType(other) + + main_types = [self.main_type, other.main_type] + sub_types = [self.sub_type, other.sub_type] + + # Main types and sub types must be defined. + if not all((*main_types, *sub_types)): + return False + + # Main types must match or one be "*", same for sub types. + for this_type, other_type in (main_types, sub_types): + if this_type != other_type and this_type != "*" and other_type != "*": + return False + + if bool(self.params) == bool(other.params): + # If both have params or neither have params, they must be identical. + result = self.params == other.params + else: + # If self has params and other does not, it's a match. + # If other has params and self does not, don't match. + result = bool(self.params or not other.params) + + return result @cached_property def quality(self): try: - quality = float(self.params.get("q", 1)) + quality = float(self._params.get("q", 1)) except ValueError: # Discard invalid values. return 1 @@ -741,7 +768,7 @@ class MediaType: return 0 elif self.sub_type == "*": return 1 - elif self.quality == 1: + elif not self.params: return 2 return 3 |
