# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: esteve@fluidinfo.com-20090330195126-0acrlpz52tgv04e6 # target_branch: ../trunk/ # testament_sha1: 7f04c737b5b3abdcc69717812cc66b0d10a62ec9 # timestamp: 2009-03-31 16:52:17 +0200 # base_revision_id: svn-v4:bbbe8e31-12d6-0310-92fd-\ # ac37d47ddeeb:trunk:26540 # # Begin patch === modified file 'twisted/web/server.py' --- twisted/web/server.py 2009-01-28 21:46:48 +0000 +++ twisted/web/server.py 2009-03-30 15:45:31 +0000 @@ -127,76 +127,86 @@ 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) + def _cbRender(body): + if body == NOT_DONE_YET: + warnings.warn( + "Returning NOT_DONE_YET is deprecated, return a Deferred instead.", + DeprecationWarning, stacklevel=2) + return + if type(body) is not types.StringType: + body = resource.ErrorPage( + http.INTERNAL_SERVER_ERROR, + "Request did not return a string", + "Request: " + html.PRE(reflect.safe_repr(self)) + "
" + + "Resource: " + html.PRE(reflect.safe_repr(resrc)) + "
" + + "Value: " + html.PRE(reflect.safe_repr(body))).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: + if self.method == "HEAD": + if len(body) > 0: + # This is a Bad Thing (RFC 2616, 9.4) + log.msg("Warning: HEAD request %s for resource %s is" + " returning a message body." + " I think I'll eat it." + % (self, resrc)) 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)s here.''' % { - 'URI': self.uri, - 'method': self.method, - 'plural': ((len(allowedMethods) > 1) and 's') or '', - 'allowed': string.join(allowedMethods, ', ') - }) - epage = resource.ErrorPage(http.NOT_ALLOWED, - "Method Not Allowed", s) - body = epage.render(self) else: - epage = resource.ErrorPage(http.NOT_IMPLEMENTED, "Huh?", - "I don't know how to treat a" - " %s request." % (self.method,)) - body = epage.render(self) - # end except UnsupportedMethod - - if body == NOT_DONE_YET: - return - if type(body) is not types.StringType: - body = resource.ErrorPage( - http.INTERNAL_SERVER_ERROR, - "Request did not return a string", - "Request: " + html.PRE(reflect.safe_repr(self)) + "
" + - "Resource: " + html.PRE(reflect.safe_repr(resrc)) + "
" + - "Value: " + html.PRE(reflect.safe_repr(body))).render(self) - - if self.method == "HEAD": - if len(body) > 0: - # This is a Bad Thing (RFC 2616, 9.4) - log.msg("Warning: HEAD request %s for resource %s is" - " returning a message body." - " I think I'll eat it." - % (self, resrc)) self.setHeader('content-length', str(len(body))) - self.write('') - else: - self.setHeader('content-length', str(len(body))) - self.write(body) - self.finish() + self.write(body) + self.finish() + + def _ebRender(fail): + r = fail.trap(UnsupportedMethod) + if r == UnsupportedMethod: + allowedMethods = fail.value.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)s here.''' % { + 'URI': self.uri, + 'method': self.method, + 'plural': ((len(allowedMethods) > 1) and 's') or '', + 'allowed': string.join(allowedMethods, ', ') + }) + epage = resource.ErrorPage(http.NOT_ALLOWED, + "Method Not Allowed", s) + body = epage.render(self) + else: + epage = resource.ErrorPage(http.NOT_IMPLEMENTED, "Huh?", + "I don't know how to treat a" + " %s request." % (self.method,)) + body = epage.render(self) + # end except UnsupportedMethod + return _cbRender(body) + + d = defer.maybeDeferred(resrc.render, self) + d.addCallbacks(_cbRender, _ebRender) + return d def processingFailed(self, reason): log.err(reason) === modified file 'twisted/web/test/test_web.py' --- twisted/web/test/test_web.py 2009-01-28 21:46:48 +0000 +++ twisted/web/test/test_web.py 2009-03-30 19:51:26 +0000 @@ -181,6 +181,15 @@ else: return "correct" +class SimpleDeferredResource(resource.Resource): + def render(self, request): + d = defer.Deferred() + if http.CACHED in (request.setLastModified(10), + request.setETag('MatchingTag')): + reactor.callLater(0, d.callback, '') + else: + reactor.callLater(0, d.callback, "correct") + return d class DummyChannel: class TCP: @@ -231,6 +240,18 @@ site.getResourceFor(DummyRequest([''])), sres2, "Got the wrong resource.") + def test_simplestSiteDeferred(self): + """ + L{Site.getResourceFor} returns the C{""} child of the root resource it + is constructed with when processing a request for I{/}. + """ + sres1 = SimpleDeferredResource() + sres2 = SimpleDeferredResource() + sres1.putChild("",sres2) + site = server.Site(sres1) + self.assertIdentical( + site.getResourceFor(DummyRequest([''])), + sres2, "Got the wrong resource.") class SessionTest(unittest.TestCase): # Begin bundle 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 ZQUdKgXe9budIUwfxdyRThQkEyJEQcA=