~soren/nova/iptables-security-groups

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/web/resource.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.web.test.test_web -*-
 
2
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
 
3
# See LICENSE for details.
 
4
 
 
5
"""
 
6
Implementation of the lowest-level Resource class.
 
7
"""
 
8
 
 
9
import warnings
 
10
 
 
11
from zope.interface import Attribute, implements, Interface
 
12
 
 
13
from twisted.web import http
 
14
 
 
15
 
 
16
class IResource(Interface):
 
17
    """
 
18
    A web resource.
 
19
    """
 
20
 
 
21
    isLeaf = Attribute(
 
22
        """
 
23
        Signal if this IResource implementor is a "leaf node" or not. If True,
 
24
        getChildWithDefault will not be called on this Resource.
 
25
        """)
 
26
 
 
27
    def getChildWithDefault(name, request):
 
28
        """
 
29
        Return a child with the given name for the given request.
 
30
        This is the external interface used by the Resource publishing
 
31
        machinery. If implementing IResource without subclassing
 
32
        Resource, it must be provided. However, if subclassing Resource,
 
33
        getChild overridden instead.
 
34
        """
 
35
 
 
36
    def putChild(path, child):
 
37
        """
 
38
        Put a child IResource implementor at the given path.
 
39
        """
 
40
 
 
41
    def render(request):
 
42
        """
 
43
        Render a request. This is called on the leaf resource for
 
44
        a request. Render must return either a string, which will
 
45
        be sent to the browser as the HTML for the request, or
 
46
        server.NOT_DONE_YET. If NOT_DONE_YET is returned,
 
47
        at some point later (in a Deferred callback, usually)
 
48
        call request.write("<html>") to write data to the request,
 
49
        and request.finish() to send the data to the browser.
 
50
        """
 
51
 
 
52
 
 
53
 
 
54
def getChildForRequest(resource, request):
 
55
    """
 
56
    Traverse resource tree to find who will handle the request.
 
57
    """
 
58
    while request.postpath and not resource.isLeaf:
 
59
        pathElement = request.postpath.pop(0)
 
60
        request.prepath.append(pathElement)
 
61
        resource = resource.getChildWithDefault(pathElement, request)
 
62
    return resource
 
63
 
 
64
 
 
65
 
 
66
class Resource:
 
67
    """
 
68
    I define a web-accessible resource.
 
69
 
 
70
    I serve 2 main purposes; one is to provide a standard representation for
 
71
    what HTTP specification calls an 'entity', and the other is to provide an
 
72
    abstract directory structure for URL retrieval.
 
73
    """
 
74
 
 
75
    implements(IResource)
 
76
 
 
77
    entityType = IResource
 
78
 
 
79
    server = None
 
80
 
 
81
    def __init__(self):
 
82
        """Initialize.
 
83
        """
 
84
        self.children = {}
 
85
 
 
86
    isLeaf = 0
 
87
 
 
88
    ### Abstract Collection Interface
 
89
 
 
90
    def listStaticNames(self):
 
91
        return self.children.keys()
 
92
 
 
93
    def listStaticEntities(self):
 
94
        return self.children.items()
 
95
 
 
96
    def listNames(self):
 
97
        return self.listStaticNames() + self.listDynamicNames()
 
98
 
 
99
    def listEntities(self):
 
100
        return self.listStaticEntities() + self.listDynamicEntities()
 
101
 
 
102
    def listDynamicNames(self):
 
103
        return []
 
104
 
 
105
    def listDynamicEntities(self, request=None):
 
106
        return []
 
107
 
 
108
    def getStaticEntity(self, name):
 
109
        return self.children.get(name)
 
110
 
 
111
    def getDynamicEntity(self, name, request):
 
112
        if not self.children.has_key(name):
 
113
            return self.getChild(name, request)
 
114
        else:
 
115
            return None
 
116
 
 
117
    def delEntity(self, name):
 
118
        del self.children[name]
 
119
 
 
120
    def reallyPutEntity(self, name, entity):
 
121
        self.children[name] = entity
 
122
 
 
123
    # Concrete HTTP interface
 
124
 
 
125
    def getChild(self, path, request):
 
126
        """
 
127
        Retrieve a 'child' resource from me.
 
128
 
 
129
        Implement this to create dynamic resource generation -- resources which
 
130
        are always available may be registered with self.putChild().
 
131
 
 
132
        This will not be called if the class-level variable 'isLeaf' is set in
 
133
        your subclass; instead, the 'postpath' attribute of the request will be
 
134
        left as a list of the remaining path elements.
 
135
 
 
136
        For example, the URL /foo/bar/baz will normally be::
 
137
 
 
138
          | site.resource.getChild('foo').getChild('bar').getChild('baz').
 
139
 
 
140
        However, if the resource returned by 'bar' has isLeaf set to true, then
 
141
        the getChild call will never be made on it.
 
142
 
 
143
        @param path: a string, describing the child
 
144
 
 
145
        @param request: a twisted.web.server.Request specifying meta-information
 
146
                        about the request that is being made for this child.
 
147
        """
 
148
        return NoResource("No such child resource.")
 
149
 
 
150
 
 
151
    def getChildWithDefault(self, path, request):
 
152
        """
 
153
        Retrieve a static or dynamically generated child resource from me.
 
154
 
 
155
        First checks if a resource was added manually by putChild, and then
 
156
        call getChild to check for dynamic resources. Only override if you want
 
157
        to affect behaviour of all child lookups, rather than just dynamic
 
158
        ones.
 
159
 
 
160
        This will check to see if I have a pre-registered child resource of the
 
161
        given name, and call getChild if I do not.
 
162
        """
 
163
        if path in self.children:
 
164
            return self.children[path]
 
165
        return self.getChild(path, request)
 
166
 
 
167
 
 
168
    def getChildForRequest(self, request):
 
169
        warnings.warn("Please use module level getChildForRequest.", DeprecationWarning, 2)
 
170
        return getChildForRequest(self, request)
 
171
 
 
172
 
 
173
    def putChild(self, path, child):
 
174
        """
 
175
        Register a static child.
 
176
 
 
177
        You almost certainly don't want '/' in your path. If you
 
178
        intended to have the root of a folder, e.g. /foo/, you want
 
179
        path to be ''.
 
180
        """
 
181
        self.children[path] = child
 
182
        child.server = self.server
 
183
 
 
184
 
 
185
    def render(self, request):
 
186
        """
 
187
        Render a given resource. See L{IResource}'s render method.
 
188
 
 
189
        I delegate to methods of self with the form 'render_METHOD'
 
190
        where METHOD is the HTTP that was used to make the
 
191
        request. Examples: render_GET, render_HEAD, render_POST, and
 
192
        so on. Generally you should implement those methods instead of
 
193
        overriding this one.
 
194
 
 
195
        render_METHOD methods are expected to return a string which
 
196
        will be the rendered page, unless the return value is
 
197
        twisted.web.server.NOT_DONE_YET, in which case it is this
 
198
        class's responsibility to write the results to
 
199
        request.write(data), then call request.finish().
 
200
 
 
201
        Old code that overrides render() directly is likewise expected
 
202
        to return a string or NOT_DONE_YET.
 
203
        """
 
204
        m = getattr(self, 'render_' + request.method, None)
 
205
        if not m:
 
206
            # This needs to be here until the deprecated subclasses of the
 
207
            # below three error resources in twisted.web.error are removed.
 
208
            from twisted.web.error import UnsupportedMethod
 
209
            raise UnsupportedMethod(getattr(self, 'allowedMethods', ()))
 
210
        return m(request)
 
211
 
 
212
 
 
213
    def render_HEAD(self, request):
 
214
        """
 
215
        Default handling of HEAD method.
 
216
 
 
217
        I just return self.render_GET(request). When method is HEAD,
 
218
        the framework will handle this correctly.
 
219
        """
 
220
        return self.render_GET(request)
 
221
 
 
222
 
 
223
 
 
224
class ErrorPage(Resource):
 
225
    """
 
226
    L{ErrorPage} is a resource which responds with a particular
 
227
    (parameterized) status and a body consisting of HTML containing some
 
228
    descriptive text.  This is useful for rendering simple error pages.
 
229
 
 
230
    @ivar template: A C{str} which will have a dictionary interpolated into
 
231
        it to generate the response body.  The dictionary has the following
 
232
        keys:
 
233
 
 
234
          - C{"code"}: The status code passed to L{ErrorPage.__init__}.
 
235
          - C{"brief"}: The brief description passed to L{ErrorPage.__init__}.
 
236
          - C{"detail"}: The detailed description passed to
 
237
            L{ErrorPage.__init__}.
 
238
 
 
239
    @ivar code: An integer status code which will be used for the response.
 
240
    @ivar brief: A short string which will be included in the response body.
 
241
    @ivar detail: A longer string which will be included in the response body.
 
242
    """
 
243
 
 
244
    template = """
 
245
<html>
 
246
  <head><title>%(code)s - %(brief)s</title></head>
 
247
  <body>
 
248
    <h1>%(brief)s</h1>
 
249
    <p>%(detail)s</p>
 
250
  </body>
 
251
</html>
 
252
"""
 
253
 
 
254
    def __init__(self, status, brief, detail):
 
255
        Resource.__init__(self)
 
256
        self.code = status
 
257
        self.brief = brief
 
258
        self.detail = detail
 
259
 
 
260
 
 
261
    def render(self, request):
 
262
        request.setResponseCode(self.code)
 
263
        request.setHeader("content-type", "text/html")
 
264
        return self.template % dict(
 
265
            code=self.code,
 
266
            brief=self.brief,
 
267
            detail=self.detail)
 
268
 
 
269
 
 
270
    def getChild(self, chnam, request):
 
271
        return self
 
272
 
 
273
 
 
274
 
 
275
class NoResource(ErrorPage):
 
276
    """
 
277
    L{NoResource} is a specialization of L{ErrorPage} which returns the HTTP
 
278
    response code I{NOT FOUND}.
 
279
    """
 
280
    def __init__(self, message="Sorry. No luck finding that resource."):
 
281
        ErrorPage.__init__(self, http.NOT_FOUND,
 
282
                           "No Such Resource",
 
283
                           message)
 
284
 
 
285
 
 
286
 
 
287
class ForbiddenResource(ErrorPage):
 
288
    """
 
289
    L{ForbiddenResource} is a specialization of L{ErrorPage} which returns the
 
290
    I{FORBIDDEN} HTTP response code.
 
291
    """
 
292
    def __init__(self, message="Sorry, resource is forbidden."):
 
293
        ErrorPage.__init__(self, http.FORBIDDEN,
 
294
                           "Forbidden Resource",
 
295
                           message)
 
296
 
 
297
 
 
298
__all__ = [
 
299
    'IResource', 'getChildForRequest',
 
300
    'Resource', 'ErrorPage', 'NoResource', 'ForbiddenResource']