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

Changeset 95

Show
Ignore:
Timestamp:
12/29/04 08:42:47
Author:
cribeiro
Message:

Ticket #59 - a bunch of changes:
- Uniform return type: internally, the cpg.response.body is always assumed to be an iterable. Simple strings are wrapped in a single-item list.
- All filters were modified to work with iterables & generators.
- The gzip filter is now based on the zlib module, and works as a generator.
- The encoding filter now checks for a content-type of 'text/html', and works on it.
- The xmlrpcfilter was added to the standard library of filters.

Files:

Legend:

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

    r81 r95  
    235235 
    236236    # Set the content-length 
    237     if cpg.response.headerMap.has_key('Content-Length') and cpg.response.headerMap['Content-Length']==0: 
    238         cpg.response.headerMap['Content-Length'] = len(cpg.response.body) 
     237    if (cpg.response.headerMap.has_key('Content-Length') and 
     238        cpg.response.headerMap['Content-Length']==0): 
     239        #body = ""  
     240        #body = ''.join(list(cpg.response.body))  # a local var is more efficient here 
     241        #body = u''.join(cpg.response.body)  # a local var is more efficient here 
     242        #body = '' 
     243        #for line in cpg.response.body: 
     244        #    print body 
     245        #    body += line 
     246        buf = StringIO.StringIO() 
     247        [buf.write(x) for x in cpg.response.body] 
     248        buf.seek(0) 
     249        cpg.response.body = [buf.read()] 
     250        cpg.response.headerMap['Content-Length'] = len(cpg.response.body[0]) 
    239251 
    240252    wfile.write('%s %s\r\n' % (cpg.response.headerMap['protocolVersion'], cpg.response.headerMap['Status'])) 
     
    251263    wfile.write('\r\n') 
    252264 
    253     applyFilterList('afterResponseHeader') 
    254  
    255     applyFilterList('beforeResponseFullBody') 
    256  
    257     # Check that the response body is a string 
    258     if type(cpg.response.body) != types.StringType: 
    259         raise cperror.WrongResponseType 
    260  
    261     wfile.write(cpg.response.body) 
     265    for line in cpg.response.body: 
     266        wfile.write(line) 
     267     
     268    # finalization hook for filter cleanup & logging purposes 
     269    applyFilterList('afterResponse') 
    262270 
    263271def handleRequest(wfile): 
     
    363371    # Remove "root" from objectPathList and join it to get objectPath 
    364372    cpg.request.objectPath = '/' + '/'.join(objectPathList[1:]) 
    365     cpg.response.body = func(*(virtualPathList + cpg.request.paramList), **(cpg.request.paramMap)) 
     373    body = func(*(virtualPathList + cpg.request.paramList), **(cpg.request.paramMap)) 
     374     
     375    # builds a uniform return type 
     376    if not isinstance(body, types.GeneratorType): 
     377        cpg.response.body = [body] 
     378    else: 
     379        cpg.response.body = body 
    366380 
    367381    if cpg.response.sendResponse: 
  • trunk/cherrypy/lib/filter/basefilter.py

    r81 r95  
    3636        pass 
    3737 
    38     def afterResponseHeader(self): 
    39         """ Called after writing the response header """ 
     38    def afterResponse(self): 
     39        """ Called after writing the response (header & body included) """ 
    4040        pass 
    4141 
    42     def beforeResponseFullBody(self): 
    43         """ Called before writing the full response body """ 
    44         pass 
    45  
    46     def beforeResponseOnTheFlyBody(self): 
    47         """ Called before writing a bit of the reponse (only used 
    48             when using "on-the-fly" response. 
    49         """ 
    50         pass 
    51  
  • trunk/cherrypy/lib/filter/baseurlfilter.py

    r72 r95  
    3131        else: 
    3232            newBaseUrl = self.baseUrl 
    33        if newBaseUrl.find("://") == -1: 
    34            # add http:// or https:// if needed         
    35            newBaseUrl = cpg.request.base[:cpg.request.base.find("://")] + "://" + newBaseUrl 
     33        if newBaseUrl.find("://") == -1: 
     34            # add http:// or https:// if needed        
     35            newBaseUrl = cpg.request.base[:cpg.request.base.find("://")] + "://" + newBaseUrl 
    3636 
    3737        cpg.request.browserUrl = cpg.request.browserUrl.replace( 
  • trunk/cherrypy/lib/filter/encodingfilter.py

    r41 r95  
    2121    """ 
    2222 
    23     def __init__(self, encoding = 'utf-8'): 
     23    def __init__(self, encoding = 'utf-8', mimeTypeList = ['text/html']): 
    2424        self.encoding = encoding 
     25        self.mimeTypeList = mimeTypeList 
    2526 
    2627    def beforeResponse(self): 
    27         if isinstance(cpg.response.body, unicode): 
    28             # Encode the response 
    29             cpg.response.body = cpg.response.body.encode(self.encoding) 
     28        ct = cpg.response.headerMap.get('Content-Type').split(';')[0] 
     29        if (ct in self.mimeTypeList): 
    3030            # Add "charset=..." to response Content-Type header 
    3131            contentType = cpg.response.headerMap.get("Content-Type") 
    3232            if contentType and 'charset' not in contentType: 
    33                 cpg.response.headerMap["Content-Type"] += "; charset=%s" % self.encoding 
     33                cpg.response.headerMap["Content-Type"] += ";charset=%s" % self.encoding 
     34            # Return a generator that encodes the sequence 
     35            cpg.response.body = self.encode_body(cpg.response.body) 
    3436 
     37    def encode_body(self, body): 
     38        for line in body: 
     39            yield line.encode(self.encoding) 
  • trunk/cherrypy/lib/filter/gzipfilter.py

    r64 r95  
    1212""" 
    1313 
    14 import gzip, StringIO 
     14import zlib 
     15import struct 
     16import time 
    1517from basefilter import BaseOutputFilter 
    1618from cherrypy import cpg 
     
    2123    """ 
    2224 
    23     def __init__(self, mimeTypeList = ['text/html']): 
     25    def __init__(self, mimeTypeList = ['text/html'], compresslevel=9): 
    2426        # List of mime-types to compress 
    2527        self.mimeTypeList = mimeTypeList 
     28        self.compresslevel = compresslevel 
    2629 
    2730    def beforeResponse(self): 
     
    3437            # Set header 
    3538            cpg.response.headerMap['Content-Encoding'] = 'gzip' 
    36             # Compress page 
    37             zbuf = StringIO.StringIO() 
    38             zfile = gzip.GzipFile(mode='wb', fileobj = zbuf, compresslevel = 9) 
    39             zfile.write(cpg.response.body) 
    40             zfile.close() 
    41             cpg.response.body = zbuf.getvalue() 
     39            # Return a generator that compresses the page 
     40            cpg.response.body = self.zip_body(cpg.response.body) 
    4241 
     42    def write_gzip_header(self): 
     43        """ 
     44        Adapted from the gzip.py standard module code 
     45        """ 
     46        header = '\037\213'      # magic header 
     47        header += '\010'         # compression method 
     48        header += '\0' 
     49        header += struct.pack("<L", long(time.time())) 
     50        header += '\002' 
     51        header += '\377' 
     52        return header 
     53             
     54    def write_gzip_trailer(self, crc, size): 
     55        footer = struct.pack("<l", crc) 
     56        footer += struct.pack("<L", size & 0xFFFFFFFFL) 
     57        return footer 
    4358 
     59    def zip_body(self, body): 
     60        # Compress page 
     61        yield self.write_gzip_header() 
     62        crc = zlib.crc32("") 
     63        size = 0 
     64        zobj = zlib.compressobj(self.compresslevel, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 0) 
     65        for line in body: 
     66            size += len(line) 
     67            crc = zlib.crc32(line, crc) 
     68            yield zobj.compress(line) 
     69        yield zobj.flush() 
     70        yield self.write_gzip_trailer(crc, size) 
  • trunk/cherrypy/lib/filter/logdebuginfofilter.py

    r41 r95  
    1515from basefilter import BaseInputFilter, BaseOutputFilter 
    1616from cherrypy import cpg 
     17from itertools import chain 
    1718 
    1819class LogDebugInfoStartFilter(BaseInputFilter, BaseOutputFilter): 
     
    3839        ct = cpg.response.headerMap.get('Content-Type') 
    3940        if (ct in self.mimeTypeList): 
     41            debuginfo = '\n' 
    4042            if self.logAsComment: 
    41                 cpg.response.body += '<!-- ' 
     43                debuginfo += '<!-- ' 
    4244            else: 
    43                 cpg.response.body += self.preTag 
     45                debuginfo += self.preTag 
    4446            logList = [] 
    4547            if self.logBuildTime: 
     
    5860                    len(dumpStr)/float(1024))) 
    5961 
    60             cpg.response.body += ', '.join(logList) 
     62            debuginfo += ', '.join(logList) 
    6163            if self.logAsComment: 
    62                 cpg.response.body += '-->' 
     64                debuginfo += '-->' 
    6365 
    64             if 'Content-Length' in cpg.response.headerMap: 
    65                 cpg.response.headerMap['Content-Length'] = len(cpg.response.body) 
    66  
     66            cpg.response.body = chain(cpg.response.body, [debuginfo]) 
  • trunk/cherrypy/lib/filter/tidyfilter.py

    r40 r95  
    3131 
    3232    def beforeResponse(self): 
     33        # the tidy filter, by its very nature it's not generator friendly,  
     34        # so we just collect the body and work with it. 
     35        originalBody = ''.join(cpg.response.body) 
     36         
    3337        ct = cpg.response.headerMap.get('Content-Type') 
    3438        if ct == 'text/html': 
     
    3741            errFile = os.path.join(self.tmpDir, 'tidy.err') 
    3842            f = open(pageFile, 'wb') 
    39             f.write(cpg.response.body) 
     43            f.write(originalBody) 
    4044            f.close() 
    4145            encoding = cpg.response.headerMap.get('Content-Encoding', '') 
     
    6064 
    6165            if newErrList: 
    62                 oldHtml = cpg.response.body 
    63                 cpg.response.body = "Wrong HTML:<br>" + cgi.escape('\n'.join(newErrList)).replace('\n','<br>') 
    64                 cpg.response.body += '<br><br>' 
     66                newBody = "Wrong HTML:<br>" + cgi.escape('\n'.join(newErrList)).replace('\n','<br>') 
     67                newBody += '<br><br>' 
    6568                i=0 
    6669                for line in oldHtml.splitlines(): 
    6770                    i += 1 
    68                     cpg.response.body += "%03d - "%i + cgi.escape(line).replace('\t','    ').replace(' ','&nbsp;') + '<br>' 
     71                    newBody += "%03d - "%i + cgi.escape(line).replace('\t','    ').replace(' ','&nbsp;') + '<br>' 
    6972 
    70                 cpg.response.headerMap['Content-Length'] = len(cpg.response.body) 
     73                cpg.response.body = [newBody] 
  • trunk/cherrypy/test/testFilter1.py

    r16 r95  
    1515code = r""" 
    1616from cherrypy import cpg 
    17 import cherrypy.lib.filter.gzipfilter as gzipfilter 
    18 import cherrypy.lib.filter.encodingfilter as encodingfilter 
    19 import cherrypy.lib.filter.generatorfilter as generatorfilter 
     17from cherrypy.lib.filter.gzipfilter import GzipFilter 
     18from cherrypy.lib.filter.encodingfilter import EncodingFilter 
    2019europoundUnicode = u'\x80\xa3' 
    2120class Root: 
    2221    _cpFilterList = [ 
    23         generatorfilter.GeneratorFilter(), 
    24         encodingfilter.EncodingFilter(), 
    25         gzipfilter.GzipFilter() 
     22        EncodingFilter(), 
     23        GzipFilter() 
    2624    ] 
    2725    def index(self): 
     
    4947    # Gzip compression doesn't always return the same exact result ! 
    5048    # So we just check that the first few bytes are the same 
    51     helper.checkPageResult('Object mapping', infoMap, code, testList, failedList, extraRequestHeader = [("Accept-Encoding", "gzip")]) 
     49    helper.checkPageResult('Filters', infoMap, code, testList, failedList, extraRequestHeader = [("Accept-Encoding", "gzip")]) 

Hosted by WebFaction

Log in as guest/cpguest to create tickets