# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: esteve@fluidinfo.com-20090331192619-j7gwbw96irvmsyqq
# target_branch: ../trunk/
# testament_sha1: 27792133b71a691a8c3b15dfd81dff9ca3164b69
# timestamp: 2009-03-31 22:07:46 +0200
# base_revision_id: svn-v4:bbbe8e31-12d6-0310-92fd-\
# ac37d47ddeeb:trunk:26540
#
# Begin patch
=== modified file 'twisted/web/resource.py'
--- twisted/web/resource.py 2009-01-25 20:40:09 +0000
+++ twisted/web/resource.py 2009-03-31 19:26:19 +0000
@@ -43,10 +43,13 @@
Render a request. This is called on the leaf resource for
a request. Render must return either a string, which will
be sent to the browser as the HTML for the request, or
- server.NOT_DONE_YET. If NOT_DONE_YET is returned,
+ a Deferred containing a string as its resoult value.
+ Render can also return server.NOT_DONE_YET, but
at some point later (in a Deferred callback, usually)
call request.write("") to write data to the request,
and request.finish() to send the data to the browser.
+ The latter behavior is deprecated in favor of returning
+ Deferreds.
"""
=== 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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
FGI5m1CrgCbRwdPjiSr1P8XckU4UJBytVwKA