1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/WebStack/Zope.py Thu Aug 26 23:12:57 2004 +0000
1.3 @@ -0,0 +1,341 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Zope classes.
1.8 +In places this resembles CGI a lot because Zope seems to recycle a lot of that
1.9 +baggage.
1.10 +"""
1.11 +
1.12 +import Generic
1.13 +from Helpers import Environment
1.14 +from Helpers.Request import Cookie
1.15 +
1.16 +class Transaction(Generic.Transaction):
1.17 +
1.18 + """
1.19 + Zope transaction interface.
1.20 + """
1.21 +
1.22 + def __init__(self, request):
1.23 +
1.24 + """
1.25 + Initialise the transaction with the Zope 'request' object.
1.26 + """
1.27 +
1.28 + self.request = request
1.29 + self.response = request.RESPONSE
1.30 + self.user = None
1.31 +
1.32 + # Request-related methods.
1.33 +
1.34 + def get_request_stream(self):
1.35 +
1.36 + """
1.37 + Returns the request stream for the transaction.
1.38 + """
1.39 +
1.40 + # NOTE: Possibly not safe.
1.41 +
1.42 + return self.request.stdin
1.43 +
1.44 + def get_request_method(self):
1.45 +
1.46 + """
1.47 + Returns the request method.
1.48 + """
1.49 +
1.50 + return self.request.environ.get("REQUEST_METHOD")
1.51 +
1.52 + def get_headers(self):
1.53 +
1.54 + """
1.55 + Returns all request headers as a dictionary-like object mapping header
1.56 + names to values.
1.57 + """
1.58 +
1.59 + return Environment.get_headers(self.request.environ)
1.60 +
1.61 + def get_header_values(self, key):
1.62 +
1.63 + """
1.64 + Returns a list of all request header values associated with the given
1.65 + 'key'. Note that according to RFC 2616, 'key' is treated as a
1.66 + case-insensitive string.
1.67 + """
1.68 +
1.69 + return self.convert_to_list(self.get_headers().get(key))
1.70 +
1.71 + def get_content_type(self):
1.72 +
1.73 + """
1.74 + Returns the content type specified on the request, along with the
1.75 + charset employed.
1.76 + """
1.77 +
1.78 + return self.parse_content_type(self.request.environ.get("CONTENT_TYPE"))
1.79 +
1.80 + def get_content_charsets(self):
1.81 +
1.82 + """
1.83 + Returns the character set preferences.
1.84 +
1.85 + NOTE: Not decently supported.
1.86 + """
1.87 +
1.88 + return self.parse_content_preferences(None)
1.89 +
1.90 + def get_content_languages(self):
1.91 +
1.92 + """
1.93 + Returns extracted language information from the transaction.
1.94 +
1.95 + NOTE: Not decently supported.
1.96 + """
1.97 +
1.98 + return self.parse_content_preferences(None)
1.99 +
1.100 + def get_path(self):
1.101 +
1.102 + """
1.103 + Returns the entire path from the request.
1.104 + """
1.105 +
1.106 + # NOTE: Based on WebStack.CGI.get_path.
1.107 +
1.108 + path = self.get_path_without_query()
1.109 + qs = self.get_query_string()
1.110 + if qs:
1.111 + path += "?"
1.112 + path += qs
1.113 + return path
1.114 +
1.115 + def get_path_without_query(self):
1.116 +
1.117 + """
1.118 + Returns the entire path from the request minus the query string.
1.119 + """
1.120 +
1.121 + # NOTE: Based on WebStack.CGI.get_path.
1.122 +
1.123 + path = self.request.environ.get("SCRIPT_NAME") or ""
1.124 + if self.request.environ.has_key("PATH_INFO"):
1.125 + path += self.request.environ["PATH_INFO"]
1.126 + return path
1.127 +
1.128 + def get_path_info(self):
1.129 +
1.130 + """
1.131 + Returns the "path info" (the part of the URL after the resource name
1.132 + handling the current request) from the request.
1.133 + """
1.134 +
1.135 + return self.request.environ.get("PATH_INFO") or ""
1.136 +
1.137 + def get_query_string(self):
1.138 +
1.139 + """
1.140 + Returns the query string from the path in the request.
1.141 + """
1.142 +
1.143 + return self.request.environ.get("QUERY_STRING") or ""
1.144 +
1.145 + # Higher level request-related methods.
1.146 +
1.147 + def get_fields_from_path(self):
1.148 +
1.149 + """
1.150 + Extracts the form fields from the path specified in the transaction. The
1.151 + underlying framework may refuse to supply fields from the path if
1.152 + handling a POST transaction.
1.153 +
1.154 + Returns a dictionary mapping field names to lists of values (even if a
1.155 + single value is associated with any given field name).
1.156 + """
1.157 +
1.158 + fields = {}
1.159 + for key, value in self.request.form.items():
1.160 + if type(value) == type([]):
1.161 + fields[key] = value
1.162 + else:
1.163 + fields[key] = [value]
1.164 + return fields
1.165 +
1.166 + def get_fields_from_body(self, encoding=None):
1.167 +
1.168 + """
1.169 + Extracts the form fields from the message body in the transaction. The
1.170 + optional 'encoding' parameter specifies the character encoding of the
1.171 + message body for cases where no such information is available, but where
1.172 + the default encoding is to be overridden.
1.173 +
1.174 + Returns a dictionary mapping field names to lists of values (even if a
1.175 + single value is associated with any given field name).
1.176 +
1.177 + NOTE: Zope doesn't distinguish between path and body fields.
1.178 + """
1.179 +
1.180 + # NOTE: Conversion to Unicode may be inappropriate.
1.181 +
1.182 + encoding = self.get_content_type().charset or encoding or "iso-8859-1"
1.183 + fields = {}
1.184 + for field_name, field_values in self.get_fields_from_path().items():
1.185 + fields[field_name] = []
1.186 + for field_value in field_values:
1.187 + fields[field_name].append(unicode(field_value, encoding))
1.188 + return fields
1.189 +
1.190 + def get_user(self):
1.191 +
1.192 + """
1.193 + Extracts user information from the transaction.
1.194 +
1.195 + Returns a username as a string or None if no user is defined.
1.196 + """
1.197 +
1.198 + if self.user is not None:
1.199 + return self.user
1.200 + else:
1.201 + return self.request.environ.get("REMOTE_USER")
1.202 +
1.203 + def get_cookies(self):
1.204 +
1.205 + """
1.206 + Obtains cookie information from the request.
1.207 +
1.208 + Returns a dictionary mapping cookie names to cookie objects.
1.209 + """
1.210 +
1.211 + cookies = {}
1.212 + for name, value in self.request.cookies.items():
1.213 + cookies[name] = Cookie(name, value)
1.214 + return cookies
1.215 +
1.216 + def get_cookie(self, cookie_name):
1.217 +
1.218 + """
1.219 + Obtains cookie information from the request.
1.220 +
1.221 + Returns a cookie object for the given 'cookie_name' or None if no such
1.222 + cookie exists.
1.223 + """
1.224 +
1.225 + return Cookie(cookie_name, self.request.cookies.get(cookie_name))
1.226 +
1.227 + # Response-related methods.
1.228 +
1.229 + def get_response_stream(self):
1.230 +
1.231 + """
1.232 + Returns the response stream for the transaction.
1.233 + """
1.234 +
1.235 + # This yields a writable object.
1.236 +
1.237 + return self.response
1.238 +
1.239 + def get_response_code(self):
1.240 +
1.241 + """
1.242 + Get the response code associated with the transaction. If no response
1.243 + code is defined, None is returned.
1.244 + """
1.245 +
1.246 + return self.response.status
1.247 +
1.248 + def set_response_code(self, response_code):
1.249 +
1.250 + """
1.251 + Set the 'response_code' using a numeric constant defined in the HTTP
1.252 + specification.
1.253 + """
1.254 +
1.255 + self.response.setStatus(response_code)
1.256 +
1.257 + def set_header_value(self, header, value):
1.258 +
1.259 + """
1.260 + Set the HTTP 'header' with the given 'value'.
1.261 + """
1.262 +
1.263 + self.response.setHeader(header, value)
1.264 +
1.265 + def set_content_type(self, content_type):
1.266 +
1.267 + """
1.268 + Sets the 'content_type' for the response.
1.269 + """
1.270 +
1.271 + self.response.setHeader("Content-Type", self.format_content_type(content_type))
1.272 +
1.273 + # Higher level response-related methods.
1.274 +
1.275 + def set_cookie(self, cookie):
1.276 +
1.277 + """
1.278 + Stores the given 'cookie' object in the response.
1.279 + """
1.280 +
1.281 + self.set_cookie_value(cookie.name, cookie.value)
1.282 +
1.283 + def set_cookie_value(self, name, value, path=None, expires=None):
1.284 +
1.285 + """
1.286 + Stores a cookie with the given 'name' and 'value' in the response.
1.287 +
1.288 + The optional 'path' is a string which specifies the scope of the cookie,
1.289 + and the optional 'expires' parameter is a value compatible with the
1.290 + time.time function, and indicates the expiry date/time of the cookie.
1.291 + """
1.292 +
1.293 + self.response.setCookie(name, value)
1.294 +
1.295 + def delete_cookie(self, cookie_name):
1.296 +
1.297 + """
1.298 + Adds to the response a request that the cookie with the given
1.299 + 'cookie_name' be deleted/discarded by the client.
1.300 + """
1.301 +
1.302 + self.response.expireCookie(cookie_name)
1.303 +
1.304 + # Session-related methods.
1.305 +
1.306 + def get_session(self, create=1):
1.307 +
1.308 + """
1.309 + Gets a session corresponding to an identifier supplied in the
1.310 + transaction.
1.311 +
1.312 + If no session has yet been established according to information
1.313 + provided in the transaction then the optional 'create' parameter
1.314 + determines whether a new session will be established.
1.315 +
1.316 + Where no session has been established and where 'create' is set to 0
1.317 + then None is returned. In all other cases, a session object is created
1.318 + (where appropriate) and returned.
1.319 + """
1.320 +
1.321 + raise NotImplementedError, "get_session"
1.322 +
1.323 + def expire_session(self):
1.324 +
1.325 + """
1.326 + Expires any session established according to information provided in the
1.327 + transaction.
1.328 + """
1.329 +
1.330 + raise NotImplementedError, "expire_session"
1.331 +
1.332 + # Application-specific methods.
1.333 +
1.334 + def set_user(self, username):
1.335 +
1.336 + """
1.337 + An application-specific method which sets the user information with
1.338 + 'username' in the transaction. This affects subsequent calls to
1.339 + 'get_user'.
1.340 + """
1.341 +
1.342 + self.user = username
1.343 +
1.344 +# vim: tabstop=4 expandtab shiftwidth=4