Ticket #3700: middleware.2.py

File middleware.2.py, 2.9 KB (added by Dave Hodder <dmh@…>, 17 years ago)

django.contrib.xhtmldegrader.middleware.py

Line 
1"""
2XHTML Degrader Middleware.
3
4When sending contents with the XHTML media type, application/xhtml+xml, this
5module checks to ensure that the user agent (web browser) is capable of
6rendering it. If not, it changes the media type to text/html and makes the
7contents more "HTML-friendly" (as per the XHTML 1.0 HTML Compatibility
8Guidelines).
9"""
10
11import re
12
13_MEDIA_TYPE_RE = re.compile(r'application\/xhtml\+xml')
14
15_EMPTY_TAG_END_RE = re.compile(r'(?<=\S)\/\>')
16
17_PROCESSING_INSTRUCTION_RE = re.compile(r'\<\?.*\?\>')
18
19_MSIE_WITHOUT_XHTML_RE = re.compile(r'\(compatible\; MSIE [1-7]\.')
20
21def _supports_xhtml(request):
22 """Examines an HTTP request header to determine whether the user agent
23 supports the XHTML media type (application/xhtml+xml). Returns True or
24 False."""
25 accept_header = request.META.get('HTTP_ACCEPT', '*/*').strip().lower()
26 if '/xhtml+xml' in accept_header or 'application/*' in accept_header \
27 or (accept_header == '*/*' and not _MSIE_WITHOUT_XHTML_RE.search(
28 request.META.get('HTTP_USER_AGENT', ''))):
29 # User agent probably supports XHTML media type.
30 return True
31 else:
32 # No reference to XHTML support.
33 return False
34
35class XhtmlDegraderMiddleware(object):
36 """Django middleware that "degrades" any contents sent as XHTML if the
37 requesting browser doesn't support the XHTML media type. Degrading involves
38 switching the content type to text/html, removing XML processing
39 instructions, etc.
40
41 If the HTTP response is already set to text/html, or set to any media type
42 other than application/xhtml+xml, this middleware will have no effect.
43 """
44
45 def process_response(self, request, response):
46 # Check if this is XHTML, and check if the user agent supports XHTML.
47 if response['Content-Type'].split(';')[0] != 'application/xhtml+xml' \
48 or _supports_xhtml(request):
49 # The content is fine, simply return it.
50 return response
51 # The content is XHTML, and the user agent doesn't support it.
52 # Fix the media type:
53 response['Content-Type'] = _MEDIA_TYPE_RE.sub('text/html',
54 response['Content-Type'], 1)
55 if 'charset' not in response['Content-Type']:
56 response['Content-Type'] += '; charset=utf-8'
57 # Modify the response contents as required:
58 # Remove any XML processing instructions:
59 response.content = _PROCESSING_INSTRUCTION_RE.sub('',
60 response.content)
61 # Ensure there's a space before the trailing '/>' of empty elements:
62 response.content = _EMPTY_TAG_END_RE.sub(' />',
63 response.content)
64 # Lose any excess whitespace:
65 response.content = response.content.strip()
66 if response.content[0:9] != '<!DOCTYPE':
67 # Add a DOCTYPE, so that the user agent isn't in "quirks" mode.
68 response.content = '<!DOCTYPE html>\n' + response.content
69 return response
Back to Top