1 #!/usr/bin/env python 2 3 """ 4 mod_python classes. 5 """ 6 7 import Generic 8 from mod_python.util import parse_qs, FieldStorage 9 from mod_python import apache 10 try: 11 from mod_python import Cookie 12 except ImportError: 13 # NOTE: Should provide an alternative implementation. 14 Cookie = None 15 16 class Transaction(Generic.Transaction): 17 18 """ 19 mod_python transaction interface. 20 """ 21 22 def __init__(self, trans): 23 24 "Initialise the transaction using the mod_python transaction 'trans'." 25 26 self.trans = trans 27 self.response_code = apache.OK 28 self.user = None 29 30 # Cached information. 31 32 self.storage_body = None 33 34 # Request-related methods. 35 36 def get_request_stream(self): 37 38 """ 39 A framework-specific method which returns the request stream for 40 the transaction. 41 """ 42 43 return self.trans 44 45 def get_request_method(self): 46 47 """ 48 A framework-specific method which gets the request method. 49 """ 50 51 return self.trans.method 52 53 def get_headers(self): 54 55 """ 56 A framework-specific method which returns all request headers as a 57 dictionary-like object mapping header names to values. 58 NOTE: If duplicate header names are permitted, then this interface will 59 NOTE: need to change. 60 """ 61 62 return self.trans.headers_in 63 64 def get_header_values(self, key): 65 66 """ 67 A framework-specific method which returns a list of all request header 68 values associated with the given 'key'. Note that according to RFC 2616, 69 'key' is treated as a case-insensitive string. 70 """ 71 72 return self.convert_to_list(self.trans.headers_in.get(key)) 73 74 def get_content_type(self): 75 76 """ 77 A framework-specific method which gets the content type specified on the 78 request, along with the charset employed. 79 """ 80 81 return self.parse_content_type(self.trans.content_type) 82 83 def get_content_charsets(self): 84 85 """ 86 Returns the character set preferences. 87 """ 88 89 return self.parse_content_preferences(self.trans.headers_in.get("Accept-Charset")) 90 91 def get_content_languages(self): 92 93 """ 94 A framework-specific method which extracts language information from 95 the transaction. 96 """ 97 98 return self.parse_content_preferences(self.trans.headers_in.get("Accept-Language")) 99 100 def get_path(self): 101 102 """ 103 A framework-specific method which gets the entire path from the request. 104 """ 105 106 return self.trans.uri 107 108 def get_path_info(self): 109 110 """ 111 A framework-specific method which gets the "path info" (the part of the 112 URL after the resource name handling the current request) from the 113 request. 114 """ 115 116 return self.trans.path_info 117 118 def get_query_string(self): 119 120 """ 121 A framework-specific method which gets the query string from the path in 122 the request. 123 """ 124 125 return self.trans.args or "" 126 127 # Higher level request-related methods. 128 129 def get_fields_from_path(self): 130 131 """ 132 A framework-specific method which extracts the form fields from the 133 path specified in the transaction. The underlying framework may refuse 134 to supply fields from the path if handling a POST transaction. 135 136 Returns a dictionary mapping field names to lists of values (even if a 137 single value is associated with any given field name). 138 """ 139 140 return parse_qs(self.get_query_string(), 1) # keep_blank_values=1 141 142 def get_fields_from_body(self): 143 144 """ 145 A framework-specific method which extracts the form fields from the 146 message body in the transaction. 147 148 Returns a dictionary mapping field names to lists of values (even if a 149 single value is associated with any given field name). 150 151 The mod_python.util.FieldStorage class may augment the fields from the 152 body with fields found in the path. 153 """ 154 155 if self.storage_body is None: 156 self.storage_body = FieldStorage(self.trans, keep_blank_values=1) 157 158 # Traverse the storage, finding each field value. 159 160 fields = {} 161 for field in self.storage_body.list: 162 if not fields.has_key(field.name): 163 fields[field.name] = [] 164 fields[field.name].append(field.value) 165 return fields 166 167 def get_user(self): 168 169 """ 170 A framework-specific method which extracts user information from the 171 transaction. 172 173 Returns a username as a string or None if no user is defined. 174 """ 175 176 if self.user is not None: 177 return self.user 178 else: 179 return self.trans.user 180 181 def get_cookies(self): 182 183 """ 184 A framework-specific method which obtains cookie information from the 185 request. 186 187 Returns a dictionary mapping cookie names to cookie objects. 188 189 NOTE: No additional information is passed to the underlying API despite 190 NOTE: support for enhanced cookies in mod_python. 191 """ 192 193 return Cookie.get_cookies(self.trans) 194 195 def get_cookie(self, cookie_name): 196 197 """ 198 A framework-specific method which obtains cookie information from the 199 request. 200 201 Returns a cookie object for the given 'cookie_name' or None if no such 202 cookie exists. 203 """ 204 205 return self.get_cookies().get(cookie_name) 206 207 # Response-related methods. 208 209 def get_response_stream(self): 210 211 """ 212 A framework-specific method which returns the response stream for 213 the transaction. 214 """ 215 216 return self.trans 217 218 def get_response_code(self): 219 220 """ 221 Get the response code associated with the transaction. If no response 222 code is defined, None is returned. 223 """ 224 225 return self.response_code 226 227 def set_response_code(self, response_code): 228 229 """ 230 Set the 'response_code' using a numeric constant defined in the HTTP 231 specification. 232 """ 233 234 self.response_code = response_code 235 236 def set_header_value(self, header, value): 237 238 """ 239 Set the HTTP 'header' with the given 'value'. 240 """ 241 242 self.trans.headers_out[self.format_header_value(header)] = self.format_header_value(value) 243 244 def set_content_type(self, content_type): 245 246 """ 247 A framework-specific method which sets the 'content_type' for the 248 response. 249 """ 250 251 self.trans.content_type = self.format_content_type(content_type) 252 253 def set_cookie(self, cookie): 254 255 """ 256 A framework-specific method which stores the given 'cookie' object in 257 the response. 258 """ 259 260 if Cookie: 261 Cookie.add_cookie(self.trans, cookie) 262 else: 263 # NOTE: Should raise an exception or provide an implementation. 264 pass 265 266 def set_cookie_value(self, name, value, path=None, expires=None): 267 268 """ 269 A framework-specific method which stores a cookie with the given 'name' 270 and 'value' in the response. 271 272 The optional 'path' is a string which specifies the scope of the cookie, 273 and the optional 'expires' parameter is a value compatible with the 274 time.time function, and indicates the expiry date/time of the cookie. 275 """ 276 277 # NOTE: We just hope that Cookie converts Unicode arguments to US-ASCII. 278 279 if Cookie: 280 cookie = Cookie.Cookie(name, value) 281 if expires is not None: 282 cookie.expires = expires 283 if path is not None: 284 cookie.path = path 285 Cookie.add_cookie(self.trans, cookie) 286 else: 287 # NOTE: Should raise an exception or provide an implementation. 288 pass 289 290 def delete_cookie(self, cookie_name): 291 292 """ 293 A framework-specific method which adds to the response a request that 294 the cookie with the given 'cookie_name' be deleted/discarded by the 295 client. 296 """ 297 298 # Create a special cookie, given that we do not know whether the browser 299 # has been sent the cookie or not. 300 # NOTE: Magic discovered in Webware. 301 302 if Cookie: 303 cookie = Cookie.Cookie(cookie_name, "") 304 cookie.path = "/" 305 cookie.expires = 0 306 cookie.max_age = 0 307 Cookie.add_cookie(self.trans, cookie) 308 else: 309 # NOTE: Should raise an exception or provide an implementation. 310 pass 311 312 # Application-specific methods. 313 314 def set_user(self, username): 315 316 """ 317 An application-specific method which sets the user information with 318 'username' in the transaction. This affects subsequent calls to 319 'get_user'. 320 """ 321 322 self.user = username 323 324 # vim: tabstop=4 expandtab shiftwidth=4