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

Changeset 837

Show
Ignore:
Timestamp:
11/26/05 14:32:53
Author:
fumanchu
Message:

Made response.body into a descriptor:

  1. Now *anytime* you set body it will coerce it to an iterable, so code outside Request.main doesn't have to be as careful/aware of how to do that.
  2. New response.collapse_body() function, which collapses the body into a single new_body string, sets response.body to [new_body], and returns new_body.
  3. New request.executeMain flag (bool), to govern whether Request.main method is called. This replaces the old behavior, where main would be called "if response.body is None". There may be custom beforeMain filters which depend on the old behavior, and need to be updated to set request.executeMain = False.
Files:

Legend:

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

    r831 r837  
    107107    def set_response(self): 
    108108        import cherrypy 
    109         cherrypy.response.status = status = self.status 
    110         cherrypy.response.headerMap['Content-Type'] = "text/html" 
     109        response = cherrypy.response 
     110        response.status = status = self.status 
     111        response.headerMap['Content-Type'] = "text/html" 
    111112         
    112113        if status in (300, 301, 302, 303, 307): 
    113114            # "The ... URI SHOULD be given by the Location field 
    114115            # in the response." 
    115             cherrypy.response.headerMap['Location'] = self.urls[0] 
     116            response.headerMap['Location'] = self.urls[0] 
    116117             
    117118            # "Unless the request method was HEAD, the entity of the response 
     
    124125                   307: "This resource has moved temporarily to <a href='%s'>%s</a>.", 
    125126                   }[status] 
    126             cherrypy.response.body = ["<br />\n".join([msg % (url, url) 
    127                                                   for url in self.urls])] 
     127            response.body = "<br />\n".join([msg % (u, u) for u in self.urls]) 
    128128        elif status == 304: 
    129129            # Not Modified. 
     
    133133             
    134134            # "The 304 response MUST NOT contain a message-body." 
    135             cherrypy.response.body = [] 
     135            response.body = None 
    136136        elif status == 305: 
    137137            # Use Proxy. 
    138138            # self.urls[0] should be the URI of the proxy. 
    139             cherrypy.response.headerMap['Location'] = self.urls[0] 
    140             cherrypy.response.body = [] 
     139            response.headerMap['Location'] = self.urls[0] 
     140            response.body = None 
    141141        else: 
    142142            raise ValueError("The %s status code is unknown." % status) 
  • trunk/cherrypy/_cphttptools.py

    r835 r837  
    2727        self.remoteHost = remoteHost 
    2828        self.scheme = scheme 
     29        self.executeMain = True 
    2930     
    3031    def run(self, requestLine, headers, rfile): 
     
    7778                     
    7879                    applyFilters('beforeMain') 
    79                     if cherrypy.response.body is None
     80                    if self.executeMain
    8081                        self.main() 
    8182                     
     
    231232                    x.args = x.args + (page_handler,) 
    232233                    raise 
    233                 cherrypy.response.body = iterable(body) 
     234                cherrypy.response.body = body 
    234235                return 
    235236            except cherrypy.InternalRedirect, x: 
     
    318319 
    319320 
     321class Body(object): 
     322    """The body of the HTTP response (the response entity).""" 
     323     
     324    def __get__(self, obj, objclass=None): 
     325        if obj is None: 
     326            # When calling on the class instead of an instance... 
     327            return self 
     328        else: 
     329            return obj._body 
     330     
     331    def __set__(self, obj, value): 
     332        # Convert the given value to an iterable object. 
     333        if isinstance(value, types.FileType): 
     334            value = cptools.fileGenerator(value) 
     335        elif isinstance(value, types.GeneratorType): 
     336            value = flattener(value) 
     337        elif isinstance(value, basestring): 
     338            # strings get wrapped in a list because iterating over a single 
     339            # item list is much faster than iterating over every character 
     340            # in a long string. 
     341            value = [value] 
     342        elif value is None: 
     343            value = [] 
     344        obj._body = value 
     345 
     346 
     347def flattener(input): 
     348    """Yield the given input, recursively iterating over each result (if needed).""" 
     349    for x in input: 
     350        if not isinstance(x, types.GeneratorType): 
     351            yield x 
     352        else: 
     353            for y in flattener(x): 
     354                yield y  
     355 
     356 
    320357class Response(object): 
    321358    """An HTTP Response.""" 
     359     
     360    body = Body() 
    322361     
    323362    def __init__(self): 
     
    336375        self.simpleCookie = Cookie.SimpleCookie() 
    337376     
     377    def collapse_body(self): 
     378        newbody = ''.join([chunk for chunk in self.body]) 
     379        self.body = newbody 
     380        return newbody 
     381     
    338382    def finalize(self): 
    339383        """Transform headerMap (and cookies) into cherrypy.response.headers.""" 
     
    361405            # but allow user code to set Content-Length if desired. 
    362406            if self.headerMap.get('Content-Length') is None: 
    363                 content = ''.join([chunk for chunk in self.body]) 
    364                 self.body = [content] 
     407                content = self.collapse_body() 
    365408                self.headerMap['Content-Length'] = len(content) 
    366409         
     
    429472        self.status, self.headers, self.body = _cputil.bareError(body) 
    430473 
    431  
    432 def iterable(body): 
    433     """Convert the given body to an iterable object.""" 
    434     if isinstance(body, types.FileType): 
    435         body = cptools.fileGenerator(body) 
    436     elif isinstance(body, types.GeneratorType): 
    437         body = flattener(body) 
    438     elif isinstance(body, basestring): 
    439         # strings get wrapped in a list because iterating over a single 
    440         # item list is much faster than iterating over every character 
    441         # in a long string. 
    442         body = [body] 
    443     elif body is None: 
    444         body = [""] 
    445     return body 
    446  
    447 def flattener(input): 
    448     """Yield the given input, recursively iterating over each result (if needed).""" 
    449     for x in input: 
    450         if not isinstance(x, types.GeneratorType): 
    451             yield x 
    452         else: 
    453             for y in flattener(x): 
    454                 yield y  
  • trunk/cherrypy/_cputil.py

    r831 r837  
    262262    response.status = status 
    263263    content = getErrorPage(status, traceback=tb, message=message) 
    264     response.body = [content] 
     264    response.body = content 
    265265    response.headerMap['Content-Length'] = len(content) 
    266266    response.headerMap['Content-Type'] = "text/html" 
     
    290290        # Since we are issuing an HTTP error status, we assume that 
    291291        # the entity is short, and we should just collapse it. 
    292         content = ''.join([chunk for chunk in response.body]
     292        content = response.collapse_body(
    293293        l = len(content) 
    294294        if l and l < s: 
    295295            # IN ADDITION: the response must be written to IE 
    296296            # in one chunk or it will still get replaced! Bah. 
    297             response.body = [content + (" " * (s - l))] 
    298         else: 
    299             response.body = [content] 
    300         response.headerMap['Content-Length'] = len(response.body[0]) 
     297            content = content + (" " * (s - l)) 
     298        response.body = content 
     299        response.headerMap['Content-Length'] = len(content) 
    301300 
    302301def formatExc(exc=None): 
  • trunk/cherrypy/filters/cachefilter.py

    r814 r837  
    114114                cherrypy._cache.totNonModified += 1 
    115115                cherrypy.response.status = "304 Not Modified" 
    116                 cherrypy.response.body = [] 
     116                cherrypy.response.body = None 
    117117            else: 
    118118                # serve it & get out from the request 
     
    131131             
    132132            # Consume the body iterable. Only do this once! 
    133             body = cherrypy.response.body = [chunk for chunk in cherrypy.response.body] 
     133            body = cherrypy.response.collapse_body() 
    134134             
    135135            if cherrypy.response.headerMap.get('Pragma', None) != 'no-cache': 
  • trunk/cherrypy/filters/encodingfilter.py

    r831 r837  
    2121                return True 
    2222        else: 
    23             response.body = ''.join([chunk for chunk in response.body]
     23            response.collapse_body(
    2424            def encode_body(encoding): 
    2525                try: 
    26                     response.body = [response.body.encode(encoding)] 
     26                    body = [] 
     27                    for chunk in response.body: 
     28                        body.append(chunk.encode(encoding)) 
     29                    response.body = body 
    2730                except UnicodeError: 
    2831                    # Try the next encoding 
  • trunk/cherrypy/filters/logdebuginfofilter.py

    r814 r837  
    2323        ct = cherrypy.response.headerMap.get('Content-Type').split(';')[0] 
    2424        if ct in mimelist: 
    25             body = ''.join([chunk for chunk in cherrypy.response.body]
     25            body = cherrypy.response.collapse_body(
    2626            debuginfo = '\n' 
    2727             
  • trunk/cherrypy/filters/nsgmlsfilter.py

    r814 r837  
    1515        # the tidy filter, by its very nature it's not generator friendly,  
    1616        # so we just collect the body and work with it. 
    17         originalBody = ''.join([chunk for chunk in cherrypy.response.body]) 
    18         cherrypy.response.body = [originalBody] 
     17        originalBody = cherrypy.response.collapse_body() 
    1918         
    2019        fct = cherrypy.response.headerMap.get('Content-Type', '') 
     
    5958                    newBody += "%03d - "%i + cgi.escape(line).replace('\t','    ').replace(' ','&nbsp;') + '<br />' 
    6059                 
    61                 cherrypy.response.body = [newBody] 
     60                cherrypy.response.body = newBody 
    6261 
  • trunk/cherrypy/filters/sessionauthenticatefilter.py

    r814 r837  
    5151            if errorMsg: 
    5252                cherrypy.response.body = loginScreen(fromPage, login = login, errorMsg = errorMsg) 
     53                cherrypy.request.executeMain = False 
    5354            else: 
    5455                cherrypy.session[sessionKey] = login 
     
    6566        if not cherrypy.session.get(sessionKey): 
    6667            cherrypy.response.body = loginScreen(cherrypy.request.browserUrl) 
     68            cherrypy.request.executeMain = False 
    6769            return 
    68  
     70         
    6971        # Everything is OK: user is logged in 
    7072        if loadUserByUsername: 
  • trunk/cherrypy/filters/staticfilter.py

    r814 r837  
    4343         
    4444        cptools.serveFile(filename) 
     45        request.executeMain = False 
    4546 
  • trunk/cherrypy/filters/tidyfilter.py

    r814 r837  
    2323        # the tidy filter, by its very nature it's not generator friendly,  
    2424        # so we just collect the body and work with it. 
    25         originalBody = ''.join([chunk for chunk in cherrypy.response.body]) 
    26         cherrypy.response.body = [originalBody] 
     25        originalBody = cherrypy.response.collapse_body() 
    2726         
    2827        fct = cherrypy.response.headerMap.get('Content-Type', '') 
     
    7473                    newBody += "%03d - "%i + cgi.escape(line).replace('\t','    ').replace(' ','&nbsp;') + '<br />' 
    7574                 
    76                 cherrypy.response.body = [newBody] 
     75                cherrypy.response.body = newBody 
    7776 
    7877            elif strictXml: 
     
    9493                    bodyFile = StringIO.StringIO() 
    9594                    traceback.print_exc(file = bodyFile) 
    96                     cherrypy.response.body = [bodyFile.getvalue()] 
     95                    cherrypy.response.body = bodyFile.getvalue() 
    9796                     
    9897                    newBody = "Wrong XML:<br />" + cgi.escape(bodyFile.getvalue().replace('\n','<br />')) 
     
    103102                        newBody += "%03d - "%i + cgi.escape(line).replace('\t','    ').replace(' ','&nbsp;') + '<br />' 
    104103                     
    105                     cherrypy.response.body = [newBody] 
     104                    cherrypy.response.body = newBody 
    106105 
  • trunk/cherrypy/filters/xmlrpcfilter.py

    r836 r837  
    9999          so CP2 will find the right method to call for you, 
    100100          based on the root's position. 
    101     beforeFinalize
     101    beforeMain
    102102        Marshalls cherrypy.response.body to xmlrpc. 
    103103        - Until resolved: cherrypy.response.body must be a python source string; 
     
    171171                args = virtual_path + cherrypy.request.paramList 
    172172                body = page_handler(*args, **cherrypy.request.paramMap) 
    173                 # Don't form an iterable like CP core main() does 
    174 ##                cherrypy.response.body = iterable(body) 
    175173                break 
    176174            except cherrypy.InternalRedirect, x: 
     
    185183                               encoding=encoding, allow_none=0) 
    186184        self.respond(body) 
     185        cherrypy.request.executeMain = False 
    187186     
    188187    def afterErrorResponse(self): 
     
    204203        response = cherrypy.response 
    205204        response.status = '200 OK' 
    206         response.body = [body] 
     205        response.body = body 
    207206        response.headerMap['Content-Type'] = 'text/xml' 
    208207        response.headerMap['Content-Length'] = len(body) 
  • trunk/cherrypy/lib/cptools.py

    r807 r837  
    108108        if cherrypy.request.headerMap['If-Modified-Since'] == strModifTime: 
    109109            response.status = "304 Not Modified" 
    110             response.body = [] 
     110            response.body = None 
    111111            if getattr(cherrypy, "debug", None): 
    112112                cherrypy.log("    Found file (304 Not Modified): %s" % path, "DEBUG") 
     
    145145                response.headerMap['Content-Length'] = r_len 
    146146                bodyfile.seek(start) 
    147                 response.body = [bodyfile.read(r_len)] 
     147                response.body = bodyfile.read(r_len) 
    148148            else: 
    149149                # Return a multipart/byteranges response. 
     
    168168        else: 
    169169            response.headerMap['Content-Length'] = c_len 
    170             response.body = fileGenerator(bodyfile) 
     170            response.body = bodyfile 
    171171    else: 
    172172        response.headerMap['Content-Length'] = c_len 
    173         response.body = fileGenerator(bodyfile) 
     173        response.body = bodyfile 
    174174    return response.body 
    175175 

Hosted by WebFaction

Log in as guest/cpguest to create tickets