# 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)) + "<br />" +
+                    "Resource: " + html.PRE(reflect.safe_repr(resrc)) + "<br />" +
+                    "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)) + "<br />" +
-                "Resource: " + html.PRE(reflect.safe_repr(resrc)) + "<br />" +
-                "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=
