summaryrefslogtreecommitdiff
path: root/django/http/request.py
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2019-11-17 13:24:10 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-01-24 14:24:59 +0100
commitd66d72f95655312c413d916add61a62928639514 (patch)
tree575b6ab25fe1ff4e60ad4e527c8fc72f973dfb18 /django/http/request.py
parentcf493e5c819f5ee49b96954f026bec722e19d9c3 (diff)
downloaddjango-d66d72f95655312c413d916add61a62928639514.tar.gz
Refs #30997 -- Added HttpRequest.accepts().
Diffstat (limited to 'django/http/request.py')
-rw-r--r--django/http/request.py51
1 files changed, 51 insertions, 0 deletions
diff --git a/django/http/request.py b/django/http/request.py
index a0bdf49312..790e4546d7 100644
--- a/django/http/request.py
+++ b/django/http/request.py
@@ -20,6 +20,8 @@ from django.utils.functional import cached_property
from django.utils.http import is_same_domain, limited_parse_qsl
from django.utils.regex_helper import _lazy_re_compile
+from .multipartparser import parse_header
+
RAISE_ERROR = object()
host_validation_re = _lazy_re_compile(r"^([a-z0-9.-]+|\[[a-f0-9]*:[a-f0-9\.:]+\])(:\d+)?$")
@@ -71,6 +73,17 @@ class HttpRequest:
def headers(self):
return HttpHeaders(self.META)
+ @cached_property
+ def accepted_types(self):
+ """Return a list of MediaType instances."""
+ return parse_accept_header(self.headers.get('Accept', '*/*'))
+
+ def accepts(self, media_type):
+ return any(
+ accepted_type.match(media_type)
+ for accepted_type in self.accepted_types
+ )
+
def _set_content_type_params(self, meta):
"""Set content_type, content_params, and encoding."""
self.content_type, self.content_params = cgi.parse_header(meta.get('CONTENT_TYPE', ''))
@@ -557,6 +570,40 @@ class QueryDict(MultiValueDict):
return '&'.join(output)
+class MediaType:
+ def __init__(self, media_type_raw_line):
+ full_type, self.params = parse_header(
+ media_type_raw_line.encode('ascii') if media_type_raw_line else b''
+ )
+ self.main_type, _, self.sub_type = full_type.partition('/')
+
+ def __str__(self):
+ params_str = ''.join(
+ '; %s=%s' % (k, v.decode('ascii'))
+ for k, v in self.params.items()
+ )
+ return '%s%s%s' % (
+ self.main_type,
+ ('/%s' % self.sub_type) if self.sub_type else '',
+ params_str,
+ )
+
+ def __repr__(self):
+ return '<%s: %s>' % (self.__class__.__qualname__, self)
+
+ @property
+ def is_all_types(self):
+ return self.main_type == '*' and self.sub_type == '*'
+
+ def match(self, other):
+ if self.is_all_types:
+ return True
+ other = MediaType(other)
+ if self.main_type == other.main_type and self.sub_type in {'*', other.sub_type}:
+ return True
+ return False
+
+
# It's neither necessary nor appropriate to use
# django.utils.encoding.force_str() for parsing URLs and form inputs. Thus,
# this slightly more restricted function, used by QueryDict.
@@ -612,3 +659,7 @@ def validate_host(host, allowed_hosts):
Return ``True`` for a valid host, ``False`` otherwise.
"""
return any(pattern == '*' or is_same_domain(host, pattern) for pattern in allowed_hosts)
+
+
+def parse_accept_header(header):
+ return [MediaType(token) for token in header.split(',') if token.strip()]