[Twisted-Python] Patch to allow deferreds to be returned from resource.render
Ooh lets try sending this mail one more time. Apparently the combined suckage of three different programs made my last mail not get through: 1) Apple Mail sucks and doesn't quote the "Full Name" automatically, so I end up with a non-RFC-conforming From: with a "." outside of quotes or the email address. 2) Exim sucks and doesn't fix it (OTOH, Sendmail does fix it, which is why i've never seen this problem before!) 3) Mailman sucks as well, and gets completely confused by this slightly non-conformant address format, and thinks my email address is "jamesy.knight". Anyways, on to the original message: === This patch lets you return a deferred from resource.render (the obvious thing to do) and have it work. As opposed to the current method where you need to return NOT_DONE_YET and restructure all your code to call request.write(...). That should still work too, though. I'd stick this on the bug tracker but I forgot my password. (anyone able to reset for me? :) James --- server.py~ Mon Jul 21 00:09:52 2003 +++ server.py Tue Sep 9 15:02:09 2003 @@ -160,56 +160,8 @@ except: self.processingFailed(failure.Failure()) - - def render(self, resrc): - try: - body = resrc.render(self) - except UnsupportedMethod, e: - allowedMethods = e.allowedMethods - if (self.method == "HEAD") and ("GET" in allowedMethods): - # We must support HEAD (RFC 2616, 5.1.1). If the - # resource doesn't, fake it by giving the resource - # a 'GET' request and then return only the headers, - # not the body. - log.msg("Using GET to fake a HEAD request for %s" % - (resrc,)) - self.method = "GET" - body = resrc.render(self) - - if body is NOT_DONE_YET: - log.msg("Tried to fake a HEAD request for %s, but " - "it got away from me." % resrc) - # Oh well, I guess we won't include the content length. - else: - self.setHeader('content-length', str(len(body))) - - self.write('') - self.finish() - return - - if self.method in (supportedMethods): - # We MUST include an Allow header - # (RFC 2616, 10.4.6 and 14.7) - self.setHeader('Allow', allowedMethods) - s = ('''Your browser approached me (at %(URI)s) with''' - ''' the method "%(method)s". I only allow''' - ''' the method%(plural)s %(allowed) here.''' % { - 'URI': self.uri, - 'method': self.method, - 'plural': ((len(allowedMethods) > 1) and 's') or '', - 'allowed': string.join(allowedMethods, ', ') - }) - epage = error.ErrorPage(http.NOT_ALLOWED, - "Method Not Allowed", s) - body = epage.render(self) - else: - epage = error.ErrorPage(http.NOT_IMPLEMENTED, "Huh?", - """I don't know how to treat a""" - """ %s request.""" - % (self.method)) - body = epage.render(self) - # end except UnsupportedMethod - + def _cbRender(self, body, resrc): + if body == NOT_DONE_YET: return if type(body) is not types.StringType: @@ -232,6 +184,58 @@ self.setHeader('content-length', str(len(body))) self.write(body) self.finish() + + def _ebRender(self, failure, resrc): + failure.trap(UnsupportedMethod) + e = failure.value + allowedMethods = e.allowedMethods + if (self.method == "HEAD") and ("GET" in allowedMethods): + # We must support HEAD (RFC 2616, 5.1.1). If the + # resource doesn't, fake it by giving the resource + # a 'GET' request and then return only the headers, + # not the body. + log.msg("Using GET to fake a HEAD request for %s" % + (resrc,)) + self.method = "GET" + body = resrc.render(self) + + if body is NOT_DONE_YET: + log.msg("Tried to fake a HEAD request for %s, but " + "it got away from me." % resrc) + # Oh well, I guess we won't include the content length. + else: + self.setHeader('content-length', str(len(body))) + + self.write('') + self.finish() + return + + if self.method in (supportedMethods): + # We MUST include an Allow header + # (RFC 2616, 10.4.6 and 14.7) + self.setHeader('Allow', allowedMethods) + s = ('''Your browser approached me (at %(URI)s) with''' + ''' the method "%(method)s". I only allow''' + ''' the method%(plural)s %(allowed) here.''' % { + 'URI': self.uri, + 'method': self.method, + 'plural': ((len(allowedMethods) > 1) and 's') or '', + 'allowed': string.join(allowedMethods, ', ') + }) + epage = error.ErrorPage(http.NOT_ALLOWED, + "Method Not Allowed", s) + body = epage.render(self) + else: + epage = error.ErrorPage(http.NOT_IMPLEMENTED, "Huh?", + """I don't know how to treat a""" + """ %s request.""" + % (self.method)) + body = epage.render(self) + + def render(self, resrc): + defer.maybeDeferred(resrc.render, self).addErrback(self._ebRender, resrc).addCallback(self._cbRender, resrc).addErrback(self.processingFailed) + + def processingFailed(self, reason): log.err(reason)
Thanks for writing this - add it to the issue tracker please so we don't lose it?
On Sun, Sep 14, 2003 at 12:06:29PM -0400, Itamar Shtull-Trauring wrote:
Thanks for writing this - add it to the issue tracker please so we don't lose it?
Uh, he said: [...]
I'd stick this on the bug tracker but I forgot my password. (anyone able to reset for me? :)
-Andrew.
participants (3)
-
Andrew Bennetts -
Itamar Shtull-Trauring -
James Y. Knight