| 7 | | |
|---|
| 8 | | def find_acceptable_charset(self): |
|---|
| 9 | | conf = cherrypy.config.get |
|---|
| 10 | | response = cherrypy.response |
|---|
| 11 | | |
|---|
| 12 | | stream = conf("streamResponse", False) |
|---|
| 13 | | if stream: |
|---|
| 14 | | # Use a generator wrapper, and just pray it works as the |
|---|
| 15 | | # stream is being written out. |
|---|
| 16 | | def encode_body(encoding): |
|---|
| 17 | | def encoder(body): |
|---|
| 18 | | for line in body: |
|---|
| 19 | | yield line.encode(encoding) |
|---|
| 20 | | response.body = encoder(response.body) |
|---|
| 21 | | return True |
|---|
| 22 | | else: |
|---|
| 23 | | response.collapse_body() |
|---|
| 24 | | def encode_body(encoding): |
|---|
| 25 | | try: |
|---|
| 26 | | body = [] |
|---|
| 27 | | for chunk in response.body: |
|---|
| 28 | | body.append(chunk.encode(encoding)) |
|---|
| 29 | | response.body = body |
|---|
| 30 | | except UnicodeError: |
|---|
| 31 | | # Try the next encoding |
|---|
| 32 | | return False |
|---|
| 33 | | else: |
|---|
| 34 | | return True |
|---|
| 35 | | |
|---|
| 36 | | failmsg = "The response could not be encoded with %s" |
|---|
| 37 | | |
|---|
| 38 | | enc = conf('encoding_filter.encoding', None) |
|---|
| 39 | | if enc is not None: |
|---|
| 40 | | # If specified, force this encoding to be used, or fail. |
|---|
| 41 | | if encode_body(enc): |
|---|
| 42 | | return enc |
|---|
| 43 | | else: |
|---|
| 44 | | raise cherrypy.HTTPError(500, failmsg % enc) |
|---|
| 45 | | |
|---|
| 46 | | # Parse the Accept_Charset request header, and try to provide one |
|---|
| 47 | | # of the requested charsets (in order of user preference). |
|---|
| 48 | | default_enc = conf('encoding_filter.default_encoding', 'utf-8') |
|---|
| 49 | | |
|---|
| 50 | | encs = cherrypy.request.headers.elements('Accept-Charset') |
|---|
| 51 | | if encs is None: |
|---|
| 52 | | # Any character-set is acceptable. |
|---|
| 53 | | if encode_body(default_enc): |
|---|
| 54 | | return default_enc |
|---|
| 55 | | else: |
|---|
| 56 | | raise cherrypy.HTTPError(500, failmsg % default_enc) |
|---|
| 57 | | else: |
|---|
| 58 | | newbody = None |
|---|
| 59 | | charsets = [enc.value.lower() for enc in encs] |
|---|
| 60 | | if "*" not in charsets: |
|---|
| 61 | | # If no "*" is present in an Accept-Charset field, then all |
|---|
| 62 | | # character sets not explicitly mentioned get a quality |
|---|
| 63 | | # value of 0, except for ISO-8859-1, which gets a quality |
|---|
| 64 | | # value of 1 if not explicitly mentioned. |
|---|
| 65 | | iso = 'iso-8859-1' |
|---|
| 66 | | if iso not in charsets: |
|---|
| 67 | | if encode_body(iso): |
|---|
| 68 | | return iso |
|---|
| 69 | | |
|---|
| 70 | | for element in encs: |
|---|
| 71 | | if element.qvalue > 0: |
|---|
| 72 | | if element.value == "*": |
|---|
| 73 | | # Matches any charset. Try our default. |
|---|
| 74 | | if encode_body(default_enc): |
|---|
| 75 | | return default_enc |
|---|
| 76 | | else: |
|---|
| 77 | | if encode_body(element.value): |
|---|
| 78 | | return element.value |
|---|
| 79 | | |
|---|
| 80 | | # No suitable encoding found. |
|---|
| 81 | | raise cherrypy.HTTPError(406) |
|---|
| | 21 | |
|---|
| | 22 | def encode_stream(encoding): |
|---|
| | 23 | """Encode a streaming response body. |
|---|
| | 24 | |
|---|
| | 25 | Use a generator wrapper, and just pray it works as the stream is |
|---|
| | 26 | being written out. |
|---|
| | 27 | """ |
|---|
| | 28 | def encoder(body): |
|---|
| | 29 | for line in body: |
|---|
| | 30 | yield line.encode(encoding) |
|---|
| | 31 | cherrypy.response.body = encoder(cherrypy.response.body) |
|---|
| | 32 | return True |
|---|
| | 33 | |
|---|
| | 34 | def encode_string(encoding): |
|---|
| | 35 | """Encode a buffered response body.""" |
|---|
| | 36 | try: |
|---|
| | 37 | body = [] |
|---|
| | 38 | for chunk in cherrypy.response.body: |
|---|
| | 39 | body.append(chunk.encode(encoding)) |
|---|
| | 40 | cherrypy.response.body = body |
|---|
| | 41 | except UnicodeError: |
|---|
| | 42 | return False |
|---|
| | 43 | else: |
|---|
| | 44 | return True |
|---|
| | 45 | |
|---|
| | 46 | def find_acceptable_charset(): |
|---|
| | 47 | conf = cherrypy.config.get |
|---|
| | 48 | response = cherrypy.response |
|---|
| | 49 | |
|---|
| | 50 | attempted_charsets = [] |
|---|
| | 51 | |
|---|
| | 52 | stream = conf("streamResponse", False) |
|---|
| | 53 | if stream: |
|---|
| | 54 | encode = encode_stream |
|---|
| | 55 | else: |
|---|
| | 56 | response.collapse_body() |
|---|
| | 57 | encode = encode_string |
|---|
| | 58 | |
|---|
| | 59 | failmsg = "The response could not be encoded with %s" |
|---|
| | 60 | |
|---|
| | 61 | enc = conf('encoding_filter.encoding', None) |
|---|
| | 62 | if enc is not None: |
|---|
| | 63 | # If specified, force this encoding to be used, or fail. |
|---|
| | 64 | if encode(enc): |
|---|
| | 65 | return enc |
|---|
| | 66 | else: |
|---|
| | 67 | raise cherrypy.HTTPError(500, failmsg % enc) |
|---|
| | 68 | |
|---|
| | 69 | # Parse the Accept_Charset request header, and try to provide one |
|---|
| | 70 | # of the requested charsets (in order of user preference). |
|---|
| | 71 | default_enc = conf('encoding_filter.default_encoding', 'utf-8') |
|---|
| | 72 | |
|---|
| | 73 | encs = cherrypy.request.headerMap.elements('Accept-Charset') |
|---|
| | 74 | if encs is None: |
|---|
| | 75 | # Any character-set is acceptable. |
|---|
| | 76 | charsets = [] |
|---|
| | 77 | if encode(default_enc): |
|---|
| | 78 | return default_enc |
|---|
| | 79 | else: |
|---|
| | 80 | raise cherrypy.HTTPError(500, failmsg % default_enc) |
|---|
| | 81 | else: |
|---|
| | 82 | charsets = [enc.value.lower() for enc in encs] |
|---|
| | 83 | if "*" not in charsets: |
|---|
| | 84 | # If no "*" is present in an Accept-Charset field, then all |
|---|
| | 85 | # character sets not explicitly mentioned get a quality |
|---|
| | 86 | # value of 0, except for ISO-8859-1, which gets a quality |
|---|
| | 87 | # value of 1 if not explicitly mentioned. |
|---|
| | 88 | iso = 'iso-8859-1' |
|---|
| | 89 | if iso not in charsets: |
|---|
| | 90 | attempted_charsets.append(iso) |
|---|
| | 91 | if encode(iso): |
|---|
| | 92 | return iso |
|---|
| | 93 | |
|---|
| | 94 | for element in encs: |
|---|
| | 95 | if element.qvalue > 0: |
|---|
| | 96 | if element.value == "*": |
|---|
| | 97 | # Matches any charset. Try our default. |
|---|
| | 98 | if default_enc not in attempted_charsets: |
|---|
| | 99 | attempted_charsets.append(default_enc) |
|---|
| | 100 | if encode(default_enc): |
|---|
| | 101 | return default_enc |
|---|
| | 102 | else: |
|---|
| | 103 | encoding = element.value |
|---|
| | 104 | if encoding not in attempted_charsets: |
|---|
| | 105 | attempted_charsets.append(encoding) |
|---|
| | 106 | if encode(encoding): |
|---|
| | 107 | return encoding |
|---|
| | 108 | |
|---|
| | 109 | # No suitable encoding found. |
|---|
| | 110 | ac = cherrypy.request.headers.get('Accept-Charset') |
|---|
| | 111 | if ac is None: |
|---|
| | 112 | msg = "Your client did not send an Accept-Charset header." |
|---|
| | 113 | else: |
|---|
| | 114 | msg = "Your client sent this Accept-Charset header: %s." % ac |
|---|
| | 115 | msg += " We tried these charsets: %s." % ", ".join(attempted_charsets) |
|---|
| | 116 | raise cherrypy.HTTPError(406, msg) |
|---|