Ticket #3711: deferred-render.patch

File deferred-render.patch, 10.2 KB (added by esteve, 6 years ago)

This patch should let Resource return a Deferred, while maintaining compatibility

  • twisted/web/server.py

    # Bazaar merge directive format 2 (Bazaar 0.90)
    # revision_id: esteve@fluidinfo.com-20090330154531-smvmdg947gmchi7a
    # target_branch: ../trunk/
    # testament_sha1: f801b703f4d6c20a800529a0cec961ea6b079e4d
    # timestamp: 2009-03-30 19:05:48 +0200
    # base_revision_id: svn-v4:bbbe8e31-12d6-0310-92fd-\
    #   ac37d47ddeeb:trunk:26540
    # 
    # Begin patch
    === modified file 'twisted/web/server.py'
     
    127127 
    128128 
    129129    def render(self, resrc): 
    130         try: 
    131             body = resrc.render(self) 
    132         except UnsupportedMethod, e: 
    133             allowedMethods = e.allowedMethods 
    134             if (self.method == "HEAD") and ("GET" in allowedMethods): 
    135                 # We must support HEAD (RFC 2616, 5.1.1).  If the 
    136                 # resource doesn't, fake it by giving the resource 
    137                 # a 'GET' request and then return only the headers, 
    138                 # not the body. 
    139                 log.msg("Using GET to fake a HEAD request for %s" % 
    140                         (resrc,)) 
    141                 self.method = "GET" 
    142                 body = resrc.render(self) 
     130        def _cbRender(body): 
     131            if body == NOT_DONE_YET: 
     132                warnings.warn( 
     133                    "Returning NOT_DONE_YET is deprecated, return a Deferred instead.", 
     134                    DeprecationWarning, stacklevel=2) 
     135                return 
     136            if type(body) is not types.StringType: 
     137                body = resource.ErrorPage( 
     138                    http.INTERNAL_SERVER_ERROR, 
     139                    "Request did not return a string", 
     140                    "Request: " + html.PRE(reflect.safe_repr(self)) + "<br />" + 
     141                    "Resource: " + html.PRE(reflect.safe_repr(resrc)) + "<br />" + 
     142                    "Value: " + html.PRE(reflect.safe_repr(body))).render(self) 
    143143 
    144                 if body is NOT_DONE_YET: 
    145                     log.msg("Tried to fake a HEAD request for %s, but " 
    146                             "it got away from me." % resrc) 
    147                     # Oh well, I guess we won't include the content length. 
    148                 else: 
     144            if self.method == "HEAD": 
     145                if len(body) > 0: 
     146                    # This is a Bad Thing (RFC 2616, 9.4) 
     147                    log.msg("Warning: HEAD request %s for resource %s is" 
     148                            " returning a message body." 
     149                            "  I think I'll eat it." 
     150                            % (self, resrc)) 
    149151                    self.setHeader('content-length', str(len(body))) 
    150  
    151152                self.write('') 
    152                 self.finish() 
    153                 return 
    154  
    155             if self.method in (supportedMethods): 
    156                 # We MUST include an Allow header 
    157                 # (RFC 2616, 10.4.6 and 14.7) 
    158                 self.setHeader('Allow', allowedMethods) 
    159                 s = ('''Your browser approached me (at %(URI)s) with''' 
    160                      ''' the method "%(method)s".  I only allow''' 
    161                      ''' the method%(plural)s %(allowed)s here.''' % { 
    162                     'URI': self.uri, 
    163                     'method': self.method, 
    164                     'plural': ((len(allowedMethods) > 1) and 's') or '', 
    165                     'allowed': string.join(allowedMethods, ', ') 
    166                     }) 
    167                 epage = resource.ErrorPage(http.NOT_ALLOWED, 
    168                                            "Method Not Allowed", s) 
    169                 body = epage.render(self) 
    170153            else: 
    171                 epage = resource.ErrorPage(http.NOT_IMPLEMENTED, "Huh?", 
    172                                            "I don't know how to treat a" 
    173                                            " %s request." % (self.method,)) 
    174                 body = epage.render(self) 
    175         # end except UnsupportedMethod 
    176  
    177         if body == NOT_DONE_YET: 
    178             return 
    179         if type(body) is not types.StringType: 
    180             body = resource.ErrorPage( 
    181                 http.INTERNAL_SERVER_ERROR, 
    182                 "Request did not return a string", 
    183                 "Request: " + html.PRE(reflect.safe_repr(self)) + "<br />" + 
    184                 "Resource: " + html.PRE(reflect.safe_repr(resrc)) + "<br />" + 
    185                 "Value: " + html.PRE(reflect.safe_repr(body))).render(self) 
    186  
    187         if self.method == "HEAD": 
    188             if len(body) > 0: 
    189                 # This is a Bad Thing (RFC 2616, 9.4) 
    190                 log.msg("Warning: HEAD request %s for resource %s is" 
    191                         " returning a message body." 
    192                         "  I think I'll eat it." 
    193                         % (self, resrc)) 
    194154                self.setHeader('content-length', str(len(body))) 
    195             self.write('') 
    196         else: 
    197             self.setHeader('content-length', str(len(body))) 
    198             self.write(body) 
    199         self.finish() 
     155                self.write(body) 
     156            self.finish() 
     157 
     158        def _ebRender(fail): 
     159            r = fail.trap(UnsupportedMethod) 
     160            if r == UnsupportedMethod: 
     161                allowedMethods = fail.value.allowedMethods 
     162 
     163                if (self.method == "HEAD") and ("GET" in allowedMethods): 
     164                    # We must support HEAD (RFC 2616, 5.1.1).  If the 
     165                    # resource doesn't, fake it by giving the resource 
     166                    # a 'GET' request and then return only the headers, 
     167                    # not the body. 
     168                    log.msg("Using GET to fake a HEAD request for %s" % 
     169                            (resrc,)) 
     170                    self.method = "GET" 
     171                    body = resrc.render(self) 
     172 
     173                    if body is NOT_DONE_YET: 
     174                        log.msg("Tried to fake a HEAD request for %s, but " 
     175                                "it got away from me." % resrc) 
     176                        # Oh well, I guess we won't include the content length. 
     177                    else: 
     178                        self.setHeader('content-length', str(len(body))) 
     179 
     180                    self.write('') 
     181                    self.finish() 
     182                    return 
     183 
     184                if self.method in (supportedMethods): 
     185                    # We MUST include an Allow header 
     186                    # (RFC 2616, 10.4.6 and 14.7) 
     187                    self.setHeader('Allow', allowedMethods) 
     188                    s = ('''Your browser approached me (at %(URI)s) with''' 
     189                         ''' the method "%(method)s".  I only allow''' 
     190                         ''' the method%(plural)s %(allowed)s here.''' % { 
     191                        'URI': self.uri, 
     192                        'method': self.method, 
     193                        'plural': ((len(allowedMethods) > 1) and 's') or '', 
     194                        'allowed': string.join(allowedMethods, ', ') 
     195                        }) 
     196                    epage = resource.ErrorPage(http.NOT_ALLOWED, 
     197                                               "Method Not Allowed", s) 
     198                    body = epage.render(self) 
     199                else: 
     200                    epage = resource.ErrorPage(http.NOT_IMPLEMENTED, "Huh?", 
     201                                               "I don't know how to treat a" 
     202                                               " %s request." % (self.method,)) 
     203                    body = epage.render(self) 
     204                # end except UnsupportedMethod 
     205                return _cbRender(body) 
     206 
     207        d = defer.maybeDeferred(resrc.render, self) 
     208        d.addCallbacks(_cbRender, _ebRender) 
     209        return d 
    200210 
    201211    def processingFailed(self, reason): 
    202212        log.err(reason)