| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
""" |
|---|
| 6 |
I contain the interfaces for several web related objects including IRequest |
|---|
| 7 |
and IResource. I am based heavily on ideas from C{nevow.inevow}. |
|---|
| 8 |
""" |
|---|
| 9 |
|
|---|
| 10 |
from zope.interface import Attribute, Interface, interface |
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
class IResource(Interface): |
|---|
| 14 |
""" |
|---|
| 15 |
An HTTP resource. |
|---|
| 16 |
|
|---|
| 17 |
I serve 2 main purposes: one is to provide a standard representation for |
|---|
| 18 |
what HTTP specification calls an 'entity', and the other is to provide an |
|---|
| 19 |
mechanism for mapping URLs to content. |
|---|
| 20 |
""" |
|---|
| 21 |
|
|---|
| 22 |
def locateChild(req, segments): |
|---|
| 23 |
""" |
|---|
| 24 |
Locate another object which can be adapted to IResource. |
|---|
| 25 |
|
|---|
| 26 |
@return: A 2-tuple of (resource, remaining-path-segments), |
|---|
| 27 |
or a deferred which will fire the above. |
|---|
| 28 |
|
|---|
| 29 |
Causes the object publishing machinery to continue on |
|---|
| 30 |
with specified resource and segments, calling the |
|---|
| 31 |
appropriate method on the specified resource. |
|---|
| 32 |
|
|---|
| 33 |
If you return (self, L{server.StopTraversal}), this |
|---|
| 34 |
instructs web2 to immediately stop the lookup stage, |
|---|
| 35 |
and switch to the rendering stage, leaving the |
|---|
| 36 |
remaining path alone for your render function to |
|---|
| 37 |
handle. |
|---|
| 38 |
""" |
|---|
| 39 |
|
|---|
| 40 |
def renderHTTP(req): |
|---|
| 41 |
""" |
|---|
| 42 |
Return an IResponse or a deferred which will fire an |
|---|
| 43 |
IResponse. This response will be written to the web browser |
|---|
| 44 |
which initiated the request. |
|---|
| 45 |
""" |
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 |
_default = object() |
|---|
| 49 |
class SpecialAdaptInterfaceClass(interface.InterfaceClass): |
|---|
| 50 |
|
|---|
| 51 |
|
|---|
| 52 |
def __call__(self, other, alternate=_default): |
|---|
| 53 |
result = super(SpecialAdaptInterfaceClass, self).__call__(other, alternate) |
|---|
| 54 |
if result is not alternate: |
|---|
| 55 |
return result |
|---|
| 56 |
|
|---|
| 57 |
result = IOldNevowResource(other, alternate) |
|---|
| 58 |
if result is not alternate: |
|---|
| 59 |
result = IResource(result) |
|---|
| 60 |
return result |
|---|
| 61 |
if alternate is not _default: |
|---|
| 62 |
return alternate |
|---|
| 63 |
raise TypeError('Could not adapt', other, self) |
|---|
| 64 |
IResource.__class__ = SpecialAdaptInterfaceClass |
|---|
| 65 |
|
|---|
| 66 |
class IOldNevowResource(Interface): |
|---|
| 67 |
|
|---|
| 68 |
""" |
|---|
| 69 |
|
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 |
def locateChild(ctx, segments): |
|---|
| 73 |
""" |
|---|
| 74 |
Locate another object which can be adapted to IResource |
|---|
| 75 |
Return a tuple of resource, path segments |
|---|
| 76 |
""" |
|---|
| 77 |
|
|---|
| 78 |
def renderHTTP(ctx): |
|---|
| 79 |
""" |
|---|
| 80 |
Return a string or a deferred which will fire a string. This string |
|---|
| 81 |
will be written to the web browser which initiated this request. |
|---|
| 82 |
|
|---|
| 83 |
Unlike iweb.IResource, this expects the incoming data to have already been read |
|---|
| 84 |
and parsed into request.args and request.content, and expects to return a |
|---|
| 85 |
string instead of a response object. |
|---|
| 86 |
""" |
|---|
| 87 |
|
|---|
| 88 |
class ICanHandleException(Interface): |
|---|
| 89 |
|
|---|
| 90 |
|
|---|
| 91 |
def renderHTTP_exception(request, failure): |
|---|
| 92 |
""" |
|---|
| 93 |
Render an exception to the given request object. |
|---|
| 94 |
""" |
|---|
| 95 |
|
|---|
| 96 |
def renderInlineException(request, reason): |
|---|
| 97 |
""" |
|---|
| 98 |
Return stan representing the exception, to be printed in the page, |
|---|
| 99 |
not replacing the page.""" |
|---|
| 100 |
|
|---|
| 101 |
|
|---|
| 102 |
|
|---|
| 103 |
class IResponse(Interface): |
|---|
| 104 |
""" |
|---|
| 105 |
I'm a response. |
|---|
| 106 |
""" |
|---|
| 107 |
code = Attribute("The HTTP response code") |
|---|
| 108 |
headers = Attribute("A http_headers.Headers instance of headers to send") |
|---|
| 109 |
stream = Attribute("A stream.IByteStream of outgoing data, or else None.") |
|---|
| 110 |
|
|---|
| 111 |
class IRequest(Interface): |
|---|
| 112 |
""" |
|---|
| 113 |
I'm a request for a web resource. |
|---|
| 114 |
""" |
|---|
| 115 |
|
|---|
| 116 |
method = Attribute("The HTTP method from the request line, e.g. GET") |
|---|
| 117 |
uri = Attribute("The raw URI from the request line. May or may not include host.") |
|---|
| 118 |
clientproto = Attribute("Protocol from the request line, e.g. HTTP/1.1") |
|---|
| 119 |
|
|---|
| 120 |
headers = Attribute("A http_headers.Headers instance of incoming headers.") |
|---|
| 121 |
stream = Attribute("A stream.IByteStream of incoming data.") |
|---|
| 122 |
|
|---|
| 123 |
def writeResponse(response): |
|---|
| 124 |
""" |
|---|
| 125 |
Write an IResponse object to the client. |
|---|
| 126 |
""" |
|---|
| 127 |
|
|---|
| 128 |
chanRequest = Attribute("The ChannelRequest. I wonder if this is public really?") |
|---|
| 129 |
|
|---|
| 130 |
|
|---|
| 131 |
from twisted.web.iweb import IRequest as IOldRequest |
|---|
| 132 |
|
|---|
| 133 |
|
|---|
| 134 |
class IChanRequestCallbacks(Interface): |
|---|
| 135 |
""" |
|---|
| 136 |
The bits that are required of a Request for interfacing with a |
|---|
| 137 |
IChanRequest object |
|---|
| 138 |
""" |
|---|
| 139 |
|
|---|
| 140 |
def __init__(chanRequest, command, path, version, contentLength, inHeaders): |
|---|
| 141 |
""" |
|---|
| 142 |
Create a new Request object. |
|---|
| 143 |
|
|---|
| 144 |
@param chanRequest: the IChanRequest object creating this request |
|---|
| 145 |
@param command: the HTTP command e.g. GET |
|---|
| 146 |
@param path: the HTTP path e.g. /foo/bar.html |
|---|
| 147 |
@param version: the parsed HTTP version e.g. (1,1) |
|---|
| 148 |
@param contentLength: how much data to expect, or None if unknown |
|---|
| 149 |
@param inHeaders: the request headers""" |
|---|
| 150 |
|
|---|
| 151 |
def process(): |
|---|
| 152 |
""" |
|---|
| 153 |
Process the request. Called as soon as it's possibly reasonable |
|---|
| 154 |
to return a response. L{handleContentComplete} may or may not |
|---|
| 155 |
have been called already. |
|---|
| 156 |
""" |
|---|
| 157 |
|
|---|
| 158 |
def handleContentChunk(data): |
|---|
| 159 |
""" |
|---|
| 160 |
Called when a piece of incoming data has been received. |
|---|
| 161 |
""" |
|---|
| 162 |
|
|---|
| 163 |
def handleContentComplete(): |
|---|
| 164 |
""" |
|---|
| 165 |
Called when the incoming data stream is finished. |
|---|
| 166 |
""" |
|---|
| 167 |
|
|---|
| 168 |
def connectionLost(reason): |
|---|
| 169 |
""" |
|---|
| 170 |
Called if the connection was lost. |
|---|
| 171 |
""" |
|---|
| 172 |
|
|---|
| 173 |
|
|---|
| 174 |
class IChanRequest(Interface): |
|---|
| 175 |
|
|---|
| 176 |
def writeIntermediateResponse(code, headers=None): |
|---|
| 177 |
""" |
|---|
| 178 |
Write a non-terminating response. |
|---|
| 179 |
|
|---|
| 180 |
Intermediate responses cannot contain data. |
|---|
| 181 |
If the channel does not support intermediate responses, do nothing. |
|---|
| 182 |
|
|---|
| 183 |
@param code: The response code. Should be in the 1xx range. |
|---|
| 184 |
@type code: int |
|---|
| 185 |
@param headers: the headers to send in the response |
|---|
| 186 |
@type headers: C{twisted.web.http_headers.Headers} |
|---|
| 187 |
""" |
|---|
| 188 |
|
|---|
| 189 |
def writeHeaders(code, headers): |
|---|
| 190 |
""" |
|---|
| 191 |
Write a final response. |
|---|
| 192 |
|
|---|
| 193 |
@param code: The response code. Should not be in the 1xx range. |
|---|
| 194 |
@type code: int |
|---|
| 195 |
@param headers: the headers to send in the response. They will |
|---|
| 196 |
be augmented with any connection-oriented headers as |
|---|
| 197 |
necessary for the protocol. |
|---|
| 198 |
@type headers: C{twisted.web.http_headers.Headers} |
|---|
| 199 |
""" |
|---|
| 200 |
|
|---|
| 201 |
def write(data): |
|---|
| 202 |
""" |
|---|
| 203 |
Write some data. |
|---|
| 204 |
|
|---|
| 205 |
@param data: the data bytes |
|---|
| 206 |
@type data: str |
|---|
| 207 |
""" |
|---|
| 208 |
|
|---|
| 209 |
def finish(): |
|---|
| 210 |
""" |
|---|
| 211 |
Finish the request, and clean up the connection if necessary. |
|---|
| 212 |
""" |
|---|
| 213 |
|
|---|
| 214 |
def abortConnection(): |
|---|
| 215 |
""" |
|---|
| 216 |
Forcibly abort the connection without cleanly closing. |
|---|
| 217 |
|
|---|
| 218 |
Use if, for example, you can't write all the data you promised. |
|---|
| 219 |
""" |
|---|
| 220 |
|
|---|
| 221 |
def registerProducer(producer, streaming): |
|---|
| 222 |
""" |
|---|
| 223 |
Register a producer with the standard API. |
|---|
| 224 |
""" |
|---|
| 225 |
|
|---|
| 226 |
def unregisterProducer(): |
|---|
| 227 |
""" |
|---|
| 228 |
Unregister a producer. |
|---|
| 229 |
""" |
|---|
| 230 |
|
|---|
| 231 |
def getHostInfo(): |
|---|
| 232 |
""" |
|---|
| 233 |
Returns a tuple of (address, socket user connected to, |
|---|
| 234 |
boolean, was it secure). Note that this should not necessarily |
|---|
| 235 |
always return the actual local socket information from |
|---|
| 236 |
twisted. E.g. in a CGI, it should use the variables coming |
|---|
| 237 |
from the invoking script. |
|---|
| 238 |
""" |
|---|
| 239 |
|
|---|
| 240 |
def getRemoteHost(): |
|---|
| 241 |
""" |
|---|
| 242 |
Returns an address of the remote host. |
|---|
| 243 |
|
|---|
| 244 |
Like L{getHostInfo}, this information may come from the real |
|---|
| 245 |
socket, or may come from additional information, depending on |
|---|
| 246 |
the transport. |
|---|
| 247 |
""" |
|---|
| 248 |
|
|---|
| 249 |
persistent = Attribute("""Whether this request supports HTTP connection persistence. May be set to False. Should not be set to other values.""") |
|---|
| 250 |
|
|---|
| 251 |
|
|---|
| 252 |
class ISite(Interface): |
|---|
| 253 |
pass |
|---|
| 254 |
|
|---|
| 255 |
__all__ = ['ICanHandleException', 'IChanRequest', 'IChanRequestCallbacks', 'IOldNevowResource', 'IOldRequest', 'IRequest', 'IResource', 'IResponse', 'ISite'] |
|---|