Index: twisted/web2/static.py =================================================================== --- twisted/web2/static.py (revision 15884) +++ twisted/web2/static.py (working copy) @@ -17,7 +17,7 @@ # Twisted Imports from twisted.python import filepath -from twisted.internet.defer import succeed, maybeDeferred +from twisted.internet.defer import maybeDeferred from zope.interface import implements class MetaDataMixin(object): @@ -74,6 +74,32 @@ return True class StaticRenderMixin(resource.RenderMixin, MetaDataMixin): + def checkPreconditions(self, request): + # + # http.checkPreconditions() gets called by the server after every + # request. Unfortunately, we need to know to bail out before request + # processing, especially for methods that modify server state (eg. PUT). + # We also would like to do so even for methods that don't, if those + # methods might be expensive to process. + # + # Unfortunately, http.checkPreconditions() doesn't work for GET and HEAD + # unless it is given a response object, so we won't check those here and + # leave it for later. + # + # Also unfortunate, having checked precoditions here for all other + # methods, the server is going to check them again after processing, + # which is, at best, redundant. + # + if request.method not in ("GET", "HEAD"): + http.checkPreconditions( + request, + entityExists = self.exists(), + etag = self.etag(), + lastModified = self.lastModified(), + ) + + super(StaticRenderMixin, self).checkPreconditions(request) + def renderHTTP(self, request): """ See L{resource.RenderMixIn.renderHTTP}. Index: twisted/web2/resource.py =================================================================== --- twisted/web2/resource.py (revision 15882) +++ twisted/web2/resource.py (working copy) @@ -25,6 +25,15 @@ self._allowed_methods = tuple([name[5:] for name in dir(self) if name.startswith('http_')]) return self._allowed_methods + def checkPreconditions(self, request): + """ + Checks all preconditions imposed by this resource upon a request made + against it. + @param request: the request to process. + @raise http.HTTPError: if any precondition fails. + """ + pass + def renderHTTP(self, request): """ See L{iweb.IResource.renderHTTP}. @@ -52,6 +61,11 @@ response.headers.setHeader("allow", self.allowedMethods()) return response + try: + self.checkPreconditions(request) + except http.HTTPError, e: + return e.response + return method(request) def http_OPTIONS(self, request):