/usr/share/pyshared/cherrypy/filters/encodingfilter.py is in python-cherrypy 2.3.0-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | import cherrypy
from basefilter import BaseFilter
class EncodingFilter(BaseFilter):
"""Filter that automatically encodes the response."""
def before_finalize(self):
conf = cherrypy.config.get
if not conf('encoding_filter.on', False):
return
ct = cherrypy.response.headers.elements("Content-Type")
if ct:
ct = ct[0]
if ct.value.lower().startswith("text/"):
# Set "charset=..." param on response Content-Type header
ct.params['charset'] = find_acceptable_charset()
cherrypy.response.headers["Content-Type"] = str(ct)
def encode_stream(encoding, errors='strict'):
"""Encode a streaming response body.
Use a generator wrapper, and just pray it works as the stream is
being written out.
"""
def encoder(body):
for chunk in body:
if isinstance(chunk, unicode):
chunk = chunk.encode(encoding, errors)
yield chunk
cherrypy.response.body = encoder(cherrypy.response.body)
return True
def encode_string(encoding, errors='strict'):
"""Encode a buffered response body."""
try:
body = []
for chunk in cherrypy.response.body:
if isinstance(chunk, unicode):
chunk = chunk.encode(encoding, errors)
body.append(chunk)
cherrypy.response.body = body
# Delete Content-Length header so finalize() recalcs it.
cherrypy.response.headers.pop("Content-Length", None)
except (LookupError, UnicodeError):
return False
else:
return True
def find_acceptable_charset():
conf = cherrypy.config.get
response = cherrypy.response
attempted_charsets = []
stream = conf("stream_response", False)
if stream:
encode = encode_stream
else:
response.collapse_body()
encode = encode_string
failmsg = "The response could not be encoded with %s"
errors = conf('encoding_filter.errors', 'strict')
enc = conf('encoding_filter.encoding', None)
if enc is not None:
# If specified, force this encoding to be used, or fail.
if encode(enc, errors):
return enc
else:
raise cherrypy.HTTPError(500, failmsg % enc)
# Parse the Accept_Charset request header, and try to provide one
# of the requested charsets (in order of user preference).
default_enc = conf('encoding_filter.default_encoding', 'utf-8')
encs = cherrypy.request.headerMap.elements('Accept-Charset')
if not encs:
# Any character-set is acceptable.
charsets = []
if encode(default_enc, errors):
return default_enc
else:
raise cherrypy.HTTPError(500, failmsg % default_enc)
else:
charsets = [enc.value.lower() for enc in encs]
if "*" not in charsets:
# If no "*" is present in an Accept-Charset field, then all
# character sets not explicitly mentioned get a quality
# value of 0, except for ISO-8859-1, which gets a quality
# value of 1 if not explicitly mentioned.
iso = 'iso-8859-1'
if iso not in charsets:
attempted_charsets.append(iso)
if encode(iso, errors):
return iso
for element in encs:
if element.qvalue > 0:
if element.value == "*":
# Matches any charset. Try our default.
if default_enc not in attempted_charsets:
attempted_charsets.append(default_enc)
if encode(default_enc, errors):
return default_enc
else:
encoding = element.value
if encoding not in attempted_charsets:
attempted_charsets.append(encoding)
if encode(encoding, errors):
return encoding
# No suitable encoding found.
ac = cherrypy.request.headers.get('Accept-Charset')
if ac is None:
msg = "Your client did not send an Accept-Charset header."
else:
msg = "Your client sent this Accept-Charset header: %s." % ac
msg += " We tried these charsets: %s." % ", ".join(attempted_charsets)
raise cherrypy.HTTPError(406, msg)
|