Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 876

Show
Ignore:
Timestamp:
12/16/05 23:47:26
Author:
fumanchu
Message:

Better error message on "no acceptable encoding".

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/filters/encodingfilter.py

    r856 r876  
    55class EncodingFilter(BaseFilter): 
    66    """Filter that automatically encodes the response.""" 
    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) 
    827     
    838    def before_finalize(self): 
     
    9116            if ct.value.lower().startswith("text/"): 
    9217                # Set "charset=..." param on response Content-Type header 
    93                 ct.params['charset'] = self.find_acceptable_charset() 
     18                ct.params['charset'] = find_acceptable_charset() 
    9419                cherrypy.response.headers["Content-Type"] = str(ct) 
    9520 
     21 
     22def 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 
     34def 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 
     46def 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) 
  • trunk/cherrypy/test/test_decodingencoding_filter.py

    r856 r876  
    6060        self.getPage('/mao_zedong', [('Accept-Charset', 'iso-8859-1, *;q=0')]) 
    6161        self.assertStatus("406 Not Acceptable") 
    62         self.assertErrorPage(406) 
     62        self.assertInBody("Your client sent this Accept-Charset header: " 
     63                          "iso-8859-1, *;q=0. We tried these charsets: " 
     64                          "iso-8859-1.") 
    6365 
    6466 

Hosted by WebFaction

Log in as guest/cpguest to create tickets